clang API Documentation

CallAndMessageChecker.cpp
Go to the documentation of this file.
00001 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This defines CallAndMessageChecker, a builtin checker that checks for various
00011 // errors of call and objc message expressions.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "ClangSACheckers.h"
00016 #include "clang/StaticAnalyzer/Core/Checker.h"
00017 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00018 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
00019 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
00020 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
00021 #include "clang/AST/ParentMap.h"
00022 #include "clang/Basic/TargetInfo.h"
00023 #include "llvm/ADT/SmallString.h"
00024 
00025 using namespace clang;
00026 using namespace ento;
00027 
00028 namespace {
00029 class CallAndMessageChecker
00030   : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > {
00031   mutable OwningPtr<BugType> BT_call_null;
00032   mutable OwningPtr<BugType> BT_call_undef;
00033   mutable OwningPtr<BugType> BT_call_arg;
00034   mutable OwningPtr<BugType> BT_msg_undef;
00035   mutable OwningPtr<BugType> BT_objc_prop_undef;
00036   mutable OwningPtr<BugType> BT_msg_arg;
00037   mutable OwningPtr<BugType> BT_msg_ret;
00038 public:
00039 
00040   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
00041   void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
00042 
00043 private:
00044   static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg,
00045                              const char *BT_desc, OwningPtr<BugType> &BT);
00046   static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
00047                                  const Expr *argEx,
00048                                  const bool checkUninitFields,
00049                                  const char *BT_desc,
00050                                  OwningPtr<BugType> &BT);
00051 
00052   static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
00053   void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
00054                           ExplodedNode *N) const;
00055 
00056   void HandleNilReceiver(CheckerContext &C,
00057                          ProgramStateRef state,
00058                          ObjCMessage msg) const;
00059 
00060   static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
00061     if (!BT)
00062       BT.reset(new BuiltinBug(desc));
00063   }
00064 };
00065 } // end anonymous namespace
00066 
00067 void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
00068                                         const CallExpr *CE) {
00069   ExplodedNode *N = C.generateSink();
00070   if (!N)
00071     return;
00072 
00073   BugReport *R = new BugReport(*BT, BT->getName(), N);
00074   R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
00075                                bugreporter::GetCalleeExpr(N), R));
00076   C.EmitReport(R);
00077 }
00078 
00079 void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
00080                                                 CallOrObjCMessage callOrMsg,
00081                                                 const char *BT_desc,
00082                                                 OwningPtr<BugType> &BT) {
00083   // Don't check for uninitialized field values in arguments if the
00084   // caller has a body that is available and we have the chance to inline it.
00085   // This is a hack, but is a reasonable compromise betweens sometimes warning
00086   // and sometimes not depending on if we decide to inline a function.
00087   const Decl *D = callOrMsg.getDecl();
00088   const bool checkUninitFields =
00089     !(C.getAnalysisManager().shouldInlineCall() &&
00090       (D && D->getBody()));
00091   
00092   for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
00093     if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
00094                            callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
00095                            checkUninitFields,
00096                            BT_desc, BT))
00097       return;
00098 }
00099 
00100 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
00101                                                SVal V, SourceRange argRange,
00102                                                const Expr *argEx,
00103                                                const bool checkUninitFields,
00104                                                const char *BT_desc,
00105                                                OwningPtr<BugType> &BT) {
00106   if (V.isUndef()) {
00107     if (ExplodedNode *N = C.generateSink()) {
00108       LazyInit_BT(BT_desc, BT);
00109 
00110       // Generate a report for this bug.
00111       BugReport *R = new BugReport(*BT, BT->getName(), N);
00112       R->addRange(argRange);
00113       if (argEx)
00114         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx,
00115                                                                    R));
00116       C.EmitReport(R);
00117     }
00118     return true;
00119   }
00120 
00121   if (!checkUninitFields)
00122     return false;
00123   
00124   if (const nonloc::LazyCompoundVal *LV =
00125         dyn_cast<nonloc::LazyCompoundVal>(&V)) {
00126 
00127     class FindUninitializedField {
00128     public:
00129       SmallVector<const FieldDecl *, 10> FieldChain;
00130     private:
00131       ASTContext &C;
00132       StoreManager &StoreMgr;
00133       MemRegionManager &MrMgr;
00134       Store store;
00135     public:
00136       FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
00137                              MemRegionManager &mrMgr, Store s)
00138       : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
00139 
00140       bool Find(const TypedValueRegion *R) {
00141         QualType T = R->getValueType();
00142         if (const RecordType *RT = T->getAsStructureType()) {
00143           const RecordDecl *RD = RT->getDecl()->getDefinition();
00144           assert(RD && "Referred record has no definition");
00145           for (RecordDecl::field_iterator I =
00146                RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
00147             const FieldRegion *FR = MrMgr.getFieldRegion(&*I, R);
00148             FieldChain.push_back(&*I);
00149             T = I->getType();
00150             if (T->getAsStructureType()) {
00151               if (Find(FR))
00152                 return true;
00153             }
00154             else {
00155               const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
00156               if (V.isUndef())
00157                 return true;
00158             }
00159             FieldChain.pop_back();
00160           }
00161         }
00162 
00163         return false;
00164       }
00165     };
00166 
00167     const LazyCompoundValData *D = LV->getCVData();
00168     FindUninitializedField F(C.getASTContext(),
00169                              C.getState()->getStateManager().getStoreManager(),
00170                              C.getSValBuilder().getRegionManager(),
00171                              D->getStore());
00172 
00173     if (F.Find(D->getRegion())) {
00174       if (ExplodedNode *N = C.generateSink()) {
00175         LazyInit_BT(BT_desc, BT);
00176         SmallString<512> Str;
00177         llvm::raw_svector_ostream os(Str);
00178         os << "Passed-by-value struct argument contains uninitialized data";
00179 
00180         if (F.FieldChain.size() == 1)
00181           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
00182         else {
00183           os << " (e.g., via the field chain: '";
00184           bool first = true;
00185           for (SmallVectorImpl<const FieldDecl *>::iterator
00186                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
00187             if (first)
00188               first = false;
00189             else
00190               os << '.';
00191             os << **DI;
00192           }
00193           os << "')";
00194         }
00195 
00196         // Generate a report for this bug.
00197         BugReport *R = new BugReport(*BT, os.str(), N);
00198         R->addRange(argRange);
00199 
00200         // FIXME: enhance track back for uninitialized value for arbitrary
00201         // memregions
00202         C.EmitReport(R);
00203       }
00204       return true;
00205     }
00206   }
00207 
00208   return false;
00209 }
00210 
00211 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
00212                                          CheckerContext &C) const{
00213 
00214   const Expr *Callee = CE->getCallee()->IgnoreParens();
00215   const LocationContext *LCtx = C.getLocationContext();
00216   SVal L = C.getState()->getSVal(Callee, LCtx);
00217 
00218   if (L.isUndef()) {
00219     if (!BT_call_undef)
00220       BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
00221                                          "uninitalized pointer value"));
00222     EmitBadCall(BT_call_undef.get(), C, CE);
00223     return;
00224   }
00225 
00226   if (isa<loc::ConcreteInt>(L)) {
00227     if (!BT_call_null)
00228       BT_call_null.reset(
00229         new BuiltinBug("Called function pointer is null (null dereference)"));
00230     EmitBadCall(BT_call_null.get(), C, CE);
00231   }
00232 
00233   PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
00234                       "Function call argument is an uninitialized value",
00235                       BT_call_arg);
00236 }
00237 
00238 void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
00239                                                 CheckerContext &C) const {
00240 
00241   ProgramStateRef state = C.getState();
00242   const LocationContext *LCtx = C.getLocationContext();
00243 
00244   // FIXME: Handle 'super'?
00245   if (const Expr *receiver = msg.getInstanceReceiver()) {
00246     SVal recVal = state->getSVal(receiver, LCtx);
00247     if (recVal.isUndef()) {
00248       if (ExplodedNode *N = C.generateSink()) {
00249         BugType *BT = 0;
00250         if (msg.isPureMessageExpr()) {
00251           if (!BT_msg_undef)
00252             BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
00253                                               "is an uninitialized value"));
00254           BT = BT_msg_undef.get();
00255         }
00256         else {
00257           if (!BT_objc_prop_undef)
00258             BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
00259                                               "uninitialized object pointer"));
00260           BT = BT_objc_prop_undef.get();
00261         }
00262         BugReport *R =
00263           new BugReport(*BT, BT->getName(), N);
00264         R->addRange(receiver->getSourceRange());
00265         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
00266                                                                    receiver,
00267                                                                    R));
00268         C.EmitReport(R);
00269       }
00270       return;
00271     } else {
00272       // Bifurcate the state into nil and non-nil ones.
00273       DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
00274   
00275       ProgramStateRef notNilState, nilState;
00276       llvm::tie(notNilState, nilState) = state->assume(receiverVal);
00277   
00278       // Handle receiver must be nil.
00279       if (nilState && !notNilState) {
00280         HandleNilReceiver(C, state, msg);
00281         return;
00282       }
00283     }
00284   }
00285 
00286   const char *bugDesc = msg.isPropertySetter() ?
00287                      "Argument for property setter is an uninitialized value"
00288                    : "Argument in message expression is an uninitialized value";
00289   // Check for any arguments that are uninitialized/undefined.
00290   PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
00291                       bugDesc, BT_msg_arg);
00292 }
00293 
00294 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
00295                                                const ObjCMessage &msg,
00296                                                ExplodedNode *N) const {
00297 
00298   if (!BT_msg_ret)
00299     BT_msg_ret.reset(
00300       new BuiltinBug("Receiver in message expression is "
00301                      "'nil' and returns a garbage value"));
00302 
00303   SmallString<200> buf;
00304   llvm::raw_svector_ostream os(buf);
00305   os << "The receiver of message '" << msg.getSelector().getAsString()
00306      << "' is nil and returns a value of type '"
00307      << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
00308 
00309   BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
00310   if (const Expr *receiver = msg.getInstanceReceiver()) {
00311     report->addRange(receiver->getSourceRange());
00312     report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
00313                                                                     receiver,
00314                                                                     report));
00315   }
00316   C.EmitReport(report);
00317 }
00318 
00319 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
00320   return (triple.getVendor() == llvm::Triple::Apple &&
00321           (triple.getOS() == llvm::Triple::IOS ||
00322            !triple.isMacOSXVersionLT(10,5)));
00323 }
00324 
00325 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
00326                                               ProgramStateRef state,
00327                                               ObjCMessage msg) const {
00328   ASTContext &Ctx = C.getASTContext();
00329 
00330   // Check the return type of the message expression.  A message to nil will
00331   // return different values depending on the return type and the architecture.
00332   QualType RetTy = msg.getType(Ctx);
00333   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
00334   const LocationContext *LCtx = C.getLocationContext();
00335 
00336   if (CanRetTy->isStructureOrClassType()) {
00337     // Structure returns are safe since the compiler zeroes them out.
00338     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
00339     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
00340     return;
00341   }
00342 
00343   // Other cases: check if sizeof(return type) > sizeof(void*)
00344   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
00345                                   .isConsumedExpr(msg.getMessageExpr())) {
00346     // Compute: sizeof(void *) and sizeof(return type)
00347     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
00348     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
00349 
00350     if (voidPtrSize < returnTypeSize &&
00351         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
00352           (Ctx.FloatTy == CanRetTy ||
00353            Ctx.DoubleTy == CanRetTy ||
00354            Ctx.LongDoubleTy == CanRetTy ||
00355            Ctx.LongLongTy == CanRetTy ||
00356            Ctx.UnsignedLongLongTy == CanRetTy))) {
00357       if (ExplodedNode *N = C.generateSink(state))
00358         emitNilReceiverBug(C, msg, N);
00359       return;
00360     }
00361 
00362     // Handle the safe cases where the return value is 0 if the
00363     // receiver is nil.
00364     //
00365     // FIXME: For now take the conservative approach that we only
00366     // return null values if we *know* that the receiver is nil.
00367     // This is because we can have surprises like:
00368     //
00369     //   ... = [[NSScreens screens] objectAtIndex:0];
00370     //
00371     // What can happen is that [... screens] could return nil, but
00372     // it most likely isn't nil.  We should assume the semantics
00373     // of this case unless we have *a lot* more knowledge.
00374     //
00375     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
00376     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
00377     return;
00378   }
00379 
00380   C.addTransition(state);
00381 }
00382 
00383 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
00384   mgr.registerChecker<CallAndMessageChecker>();
00385 }