Home | History | Annotate | Download | only in Checkers
      1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This defines CallAndMessageChecker, a builtin checker that checks for various
     11 // errors of call and objc message expressions.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "ClangSACheckers.h"
     16 #include "clang/StaticAnalyzer/Core/Checker.h"
     17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     19 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
     20 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     21 #include "clang/AST/ParentMap.h"
     22 #include "clang/Basic/TargetInfo.h"
     23 #include "llvm/ADT/SmallString.h"
     24 
     25 using namespace clang;
     26 using namespace ento;
     27 
     28 namespace {
     29 class CallAndMessageChecker
     30   : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > {
     31   mutable OwningPtr<BugType> BT_call_null;
     32   mutable OwningPtr<BugType> BT_call_undef;
     33   mutable OwningPtr<BugType> BT_call_arg;
     34   mutable OwningPtr<BugType> BT_msg_undef;
     35   mutable OwningPtr<BugType> BT_objc_prop_undef;
     36   mutable OwningPtr<BugType> BT_msg_arg;
     37   mutable OwningPtr<BugType> BT_msg_ret;
     38 public:
     39 
     40   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
     41   void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
     42 
     43 private:
     44   static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg,
     45                              const char *BT_desc, OwningPtr<BugType> &BT);
     46   static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
     47                                  const Expr *argEx,
     48                                  const bool checkUninitFields,
     49                                  const char *BT_desc,
     50                                  OwningPtr<BugType> &BT);
     51 
     52   static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
     53   void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
     54                           ExplodedNode *N) const;
     55 
     56   void HandleNilReceiver(CheckerContext &C,
     57                          ProgramStateRef state,
     58                          ObjCMessage msg) const;
     59 
     60   static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
     61     if (!BT)
     62       BT.reset(new BuiltinBug(desc));
     63   }
     64 };
     65 } // end anonymous namespace
     66 
     67 void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
     68                                         const CallExpr *CE) {
     69   ExplodedNode *N = C.generateSink();
     70   if (!N)
     71     return;
     72 
     73   BugReport *R = new BugReport(*BT, BT->getName(), N);
     74   R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
     75                                bugreporter::GetCalleeExpr(N), R));
     76   C.EmitReport(R);
     77 }
     78 
     79 void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
     80                                                 CallOrObjCMessage callOrMsg,
     81                                                 const char *BT_desc,
     82                                                 OwningPtr<BugType> &BT) {
     83   // Don't check for uninitialized field values in arguments if the
     84   // caller has a body that is available and we have the chance to inline it.
     85   // This is a hack, but is a reasonable compromise betweens sometimes warning
     86   // and sometimes not depending on if we decide to inline a function.
     87   const Decl *D = callOrMsg.getDecl();
     88   const bool checkUninitFields =
     89     !(C.getAnalysisManager().shouldInlineCall() &&
     90       (D && D->getBody()));
     91 
     92   for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
     93     if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
     94                            callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
     95                            checkUninitFields,
     96                            BT_desc, BT))
     97       return;
     98 }
     99 
    100 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
    101                                                SVal V, SourceRange argRange,
    102                                                const Expr *argEx,
    103                                                const bool checkUninitFields,
    104                                                const char *BT_desc,
    105                                                OwningPtr<BugType> &BT) {
    106   if (V.isUndef()) {
    107     if (ExplodedNode *N = C.generateSink()) {
    108       LazyInit_BT(BT_desc, BT);
    109 
    110       // Generate a report for this bug.
    111       BugReport *R = new BugReport(*BT, BT->getName(), N);
    112       R->addRange(argRange);
    113       if (argEx)
    114         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx,
    115                                                                    R));
    116       C.EmitReport(R);
    117     }
    118     return true;
    119   }
    120 
    121   if (!checkUninitFields)
    122     return false;
    123 
    124   if (const nonloc::LazyCompoundVal *LV =
    125         dyn_cast<nonloc::LazyCompoundVal>(&V)) {
    126 
    127     class FindUninitializedField {
    128     public:
    129       SmallVector<const FieldDecl *, 10> FieldChain;
    130     private:
    131       ASTContext &C;
    132       StoreManager &StoreMgr;
    133       MemRegionManager &MrMgr;
    134       Store store;
    135     public:
    136       FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
    137                              MemRegionManager &mrMgr, Store s)
    138       : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
    139 
    140       bool Find(const TypedValueRegion *R) {
    141         QualType T = R->getValueType();
    142         if (const RecordType *RT = T->getAsStructureType()) {
    143           const RecordDecl *RD = RT->getDecl()->getDefinition();
    144           assert(RD && "Referred record has no definition");
    145           for (RecordDecl::field_iterator I =
    146                RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
    147             const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
    148             FieldChain.push_back(*I);
    149             T = (*I)->getType();
    150             if (T->getAsStructureType()) {
    151               if (Find(FR))
    152                 return true;
    153             }
    154             else {
    155               const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
    156               if (V.isUndef())
    157                 return true;
    158             }
    159             FieldChain.pop_back();
    160           }
    161         }
    162 
    163         return false;
    164       }
    165     };
    166 
    167     const LazyCompoundValData *D = LV->getCVData();
    168     FindUninitializedField F(C.getASTContext(),
    169                              C.getState()->getStateManager().getStoreManager(),
    170                              C.getSValBuilder().getRegionManager(),
    171                              D->getStore());
    172 
    173     if (F.Find(D->getRegion())) {
    174       if (ExplodedNode *N = C.generateSink()) {
    175         LazyInit_BT(BT_desc, BT);
    176         SmallString<512> Str;
    177         llvm::raw_svector_ostream os(Str);
    178         os << "Passed-by-value struct argument contains uninitialized data";
    179 
    180         if (F.FieldChain.size() == 1)
    181           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
    182         else {
    183           os << " (e.g., via the field chain: '";
    184           bool first = true;
    185           for (SmallVectorImpl<const FieldDecl *>::iterator
    186                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
    187             if (first)
    188               first = false;
    189             else
    190               os << '.';
    191             os << **DI;
    192           }
    193           os << "')";
    194         }
    195 
    196         // Generate a report for this bug.
    197         BugReport *R = new BugReport(*BT, os.str(), N);
    198         R->addRange(argRange);
    199 
    200         // FIXME: enhance track back for uninitialized value for arbitrary
    201         // memregions
    202         C.EmitReport(R);
    203       }
    204       return true;
    205     }
    206   }
    207 
    208   return false;
    209 }
    210 
    211 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
    212                                          CheckerContext &C) const{
    213 
    214   const Expr *Callee = CE->getCallee()->IgnoreParens();
    215   const LocationContext *LCtx = C.getLocationContext();
    216   SVal L = C.getState()->getSVal(Callee, LCtx);
    217 
    218   if (L.isUndef()) {
    219     if (!BT_call_undef)
    220       BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
    221                                          "uninitalized pointer value"));
    222     EmitBadCall(BT_call_undef.get(), C, CE);
    223     return;
    224   }
    225 
    226   if (isa<loc::ConcreteInt>(L)) {
    227     if (!BT_call_null)
    228       BT_call_null.reset(
    229         new BuiltinBug("Called function pointer is null (null dereference)"));
    230     EmitBadCall(BT_call_null.get(), C, CE);
    231   }
    232 
    233   PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
    234                       "Function call argument is an uninitialized value",
    235                       BT_call_arg);
    236 }
    237 
    238 void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
    239                                                 CheckerContext &C) const {
    240 
    241   ProgramStateRef state = C.getState();
    242   const LocationContext *LCtx = C.getLocationContext();
    243 
    244   // FIXME: Handle 'super'?
    245   if (const Expr *receiver = msg.getInstanceReceiver()) {
    246     SVal recVal = state->getSVal(receiver, LCtx);
    247     if (recVal.isUndef()) {
    248       if (ExplodedNode *N = C.generateSink()) {
    249         BugType *BT = 0;
    250         if (msg.isPureMessageExpr()) {
    251           if (!BT_msg_undef)
    252             BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
    253                                               "is an uninitialized value"));
    254           BT = BT_msg_undef.get();
    255         }
    256         else {
    257           if (!BT_objc_prop_undef)
    258             BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
    259                                               "uninitialized object pointer"));
    260           BT = BT_objc_prop_undef.get();
    261         }
    262         BugReport *R =
    263           new BugReport(*BT, BT->getName(), N);
    264         R->addRange(receiver->getSourceRange());
    265         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
    266                                                                    receiver,
    267                                                                    R));
    268         C.EmitReport(R);
    269       }
    270       return;
    271     } else {
    272       // Bifurcate the state into nil and non-nil ones.
    273       DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
    274 
    275       ProgramStateRef notNilState, nilState;
    276       llvm::tie(notNilState, nilState) = state->assume(receiverVal);
    277 
    278       // Handle receiver must be nil.
    279       if (nilState && !notNilState) {
    280         HandleNilReceiver(C, state, msg);
    281         return;
    282       }
    283     }
    284   }
    285 
    286   const char *bugDesc = msg.isPropertySetter() ?
    287                      "Argument for property setter is an uninitialized value"
    288                    : "Argument in message expression is an uninitialized value";
    289   // Check for any arguments that are uninitialized/undefined.
    290   PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
    291                       bugDesc, BT_msg_arg);
    292 }
    293 
    294 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
    295                                                const ObjCMessage &msg,
    296                                                ExplodedNode *N) const {
    297 
    298   if (!BT_msg_ret)
    299     BT_msg_ret.reset(
    300       new BuiltinBug("Receiver in message expression is "
    301                      "'nil' and returns a garbage value"));
    302 
    303   SmallString<200> buf;
    304   llvm::raw_svector_ostream os(buf);
    305   os << "The receiver of message '" << msg.getSelector().getAsString()
    306      << "' is nil and returns a value of type '"
    307      << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
    308 
    309   BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
    310   if (const Expr *receiver = msg.getInstanceReceiver()) {
    311     report->addRange(receiver->getSourceRange());
    312     report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
    313                                                                     receiver,
    314                                                                     report));
    315   }
    316   C.EmitReport(report);
    317 }
    318 
    319 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
    320   return (triple.getVendor() == llvm::Triple::Apple &&
    321           (triple.getOS() == llvm::Triple::IOS ||
    322            !triple.isMacOSXVersionLT(10,5)));
    323 }
    324 
    325 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
    326                                               ProgramStateRef state,
    327                                               ObjCMessage msg) const {
    328   ASTContext &Ctx = C.getASTContext();
    329 
    330   // Check the return type of the message expression.  A message to nil will
    331   // return different values depending on the return type and the architecture.
    332   QualType RetTy = msg.getType(Ctx);
    333   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
    334   const LocationContext *LCtx = C.getLocationContext();
    335 
    336   if (CanRetTy->isStructureOrClassType()) {
    337     // Structure returns are safe since the compiler zeroes them out.
    338     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
    339     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
    340     return;
    341   }
    342 
    343   // Other cases: check if sizeof(return type) > sizeof(void*)
    344   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
    345                                   .isConsumedExpr(msg.getMessageExpr())) {
    346     // Compute: sizeof(void *) and sizeof(return type)
    347     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    348     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
    349 
    350     if (voidPtrSize < returnTypeSize &&
    351         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
    352           (Ctx.FloatTy == CanRetTy ||
    353            Ctx.DoubleTy == CanRetTy ||
    354            Ctx.LongDoubleTy == CanRetTy ||
    355            Ctx.LongLongTy == CanRetTy ||
    356            Ctx.UnsignedLongLongTy == CanRetTy))) {
    357       if (ExplodedNode *N = C.generateSink(state))
    358         emitNilReceiverBug(C, msg, N);
    359       return;
    360     }
    361 
    362     // Handle the safe cases where the return value is 0 if the
    363     // receiver is nil.
    364     //
    365     // FIXME: For now take the conservative approach that we only
    366     // return null values if we *know* that the receiver is nil.
    367     // This is because we can have surprises like:
    368     //
    369     //   ... = [[NSScreens screens] objectAtIndex:0];
    370     //
    371     // What can happen is that [... screens] could return nil, but
    372     // it most likely isn't nil.  We should assume the semantics
    373     // of this case unless we have *a lot* more knowledge.
    374     //
    375     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
    376     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
    377     return;
    378   }
    379 
    380   C.addTransition(state);
    381 }
    382 
    383 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
    384   mgr.registerChecker<CallAndMessageChecker>();
    385 }
    386