CallAndMessageChecker.cpp revision 55037cdc2e29b70df2fd1ca0ba9d4c36da1049e8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// License. See LICENSE.TXT for details. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This defines CallAndMessageChecker, a builtin checker that checks for various 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// errors of call and objc message expressions. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ClangSACheckers.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/Checker.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerManager.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/ParentMap.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/TargetInfo.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/SmallString.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace ento; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CallAndMessageChecker 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable OwningPtr<BugType> BT_call_null; 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mutable OwningPtr<BugType> BT_call_undef; 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mutable OwningPtr<BugType> BT_call_arg; 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mutable OwningPtr<BugType> BT_msg_undef; 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mutable OwningPtr<BugType> BT_objc_prop_undef; 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mutable OwningPtr<BugType> BT_msg_arg; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable OwningPtr<BugType> BT_msg_ret; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)public: 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private: 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void PreVisitProcessArgs(CheckerContext &C, const CallEvent &Call, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *BT_desc, OwningPtr<BugType> &BT); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Expr *argEx, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool checkUninitFields, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *BT_desc, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OwningPtr<BugType> &BT); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExplodedNode *N) const; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void HandleNilReceiver(CheckerContext &C, 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ProgramStateRef state, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ObjCMessage msg) const; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!BT) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BT.reset(new BuiltinBug(desc)); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // end anonymous namespace 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CallExpr *CE) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExplodedNode *N = C.generateSink(); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!N) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BugReport *R = new BugReport(*BT, BT->getName(), N); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bugreporter::GetCalleeExpr(N), R)); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) C.EmitReport(R); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const CallEvent &Call, 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char *BT_desc, 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OwningPtr<BugType> &BT) { 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Don't check for uninitialized field values in arguments if the 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // caller has a body that is available and we have the chance to inline it. 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This is a hack, but is a reasonable compromise betweens sometimes warning 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // and sometimes not depending on if we decide to inline a function. 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Decl *D = Call.getDecl(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool checkUninitFields = 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !(C.getAnalysisManager().shouldInlineCall() && 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (D && D->getBody())); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (PreVisitProcessArg(C, Call.getArgSVal(i), 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Call.getArgSourceRange(i), Call.getArgExpr(i), 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) checkUninitFields, BT_desc, BT)) 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SVal V, SourceRange argRange, 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Expr *argEx, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool checkUninitFields, 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *BT_desc, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OwningPtr<BugType> &BT) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (V.isUndef()) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ExplodedNode *N = C.generateSink()) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LazyInit_BT(BT_desc, BT); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Generate a report for this bug. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BugReport *R = new BugReport(*BT, BT->getName(), N); 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) R->addRange(argRange); 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (argEx) 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx, 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) R)); 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) C.EmitReport(R); 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!checkUninitFields) 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (const nonloc::LazyCompoundVal *LV = 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dyn_cast<nonloc::LazyCompoundVal>(&V)) { 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) class FindUninitializedField { 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SmallVector<const FieldDecl *, 10> FieldChain; 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StoreManager &StoreMgr; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemRegionManager &MrMgr; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Store store; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindUninitializedField(StoreManager &storeMgr, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemRegionManager &mrMgr, Store s) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Find(const TypedValueRegion *R) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QualType T = R->getValueType(); 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (const RecordType *RT = T->getAsStructureType()) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const RecordDecl *RD = RT->getDecl()->getDefinition(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(RD && "Referred record has no definition"); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (RecordDecl::field_iterator I = 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RD->field_begin(), E = RD->field_end(); I!=E; ++I) { 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const FieldRegion *FR = MrMgr.getFieldRegion(*I, R); 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) FieldChain.push_back(*I); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T = I->getType(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (T->getAsStructureType()) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Find(FR)) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else { 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR)); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (V.isUndef()) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FieldChain.pop_back(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LazyCompoundValData *D = LV->getCVData(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindUninitializedField F(C.getState()->getStateManager().getStoreManager(), 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) C.getSValBuilder().getRegionManager(), 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D->getStore()); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (F.Find(D->getRegion())) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ExplodedNode *N = C.generateSink()) { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LazyInit_BT(BT_desc, BT); 174 SmallString<512> Str; 175 llvm::raw_svector_ostream os(Str); 176 os << "Passed-by-value struct argument contains uninitialized data"; 177 178 if (F.FieldChain.size() == 1) 179 os << " (e.g., field: '" << *F.FieldChain[0] << "')"; 180 else { 181 os << " (e.g., via the field chain: '"; 182 bool first = true; 183 for (SmallVectorImpl<const FieldDecl *>::iterator 184 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ 185 if (first) 186 first = false; 187 else 188 os << '.'; 189 os << **DI; 190 } 191 os << "')"; 192 } 193 194 // Generate a report for this bug. 195 BugReport *R = new BugReport(*BT, os.str(), N); 196 R->addRange(argRange); 197 198 // FIXME: enhance track back for uninitialized value for arbitrary 199 // memregions 200 C.EmitReport(R); 201 } 202 return true; 203 } 204 } 205 206 return false; 207} 208 209void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, 210 CheckerContext &C) const{ 211 212 const Expr *Callee = CE->getCallee()->IgnoreParens(); 213 ProgramStateRef State = C.getState(); 214 const LocationContext *LCtx = C.getLocationContext(); 215 SVal L = State->getSVal(Callee, LCtx); 216 217 if (L.isUndef()) { 218 if (!BT_call_undef) 219 BT_call_undef.reset(new BuiltinBug("Called function pointer is an " 220 "uninitalized pointer value")); 221 EmitBadCall(BT_call_undef.get(), C, CE); 222 return; 223 } 224 225 if (L.isZeroConstant()) { 226 if (!BT_call_null) 227 BT_call_null.reset( 228 new BuiltinBug("Called function pointer is null (null dereference)")); 229 EmitBadCall(BT_call_null.get(), C, CE); 230 } 231 232 // FIXME: This tree of switching can go away if/when we add a check::postCall. 233 if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { 234 BlockCall Call(CE, State, LCtx); 235 PreVisitProcessArgs(C, Call, 236 "Block call argument is an uninitialized value", 237 BT_call_arg); 238 } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) { 239 CXXMemberCall Call(me, State, LCtx); 240 PreVisitProcessArgs(C, Call, 241 "Function call argument is an uninitialized value", 242 BT_call_arg); 243 } else { 244 FunctionCall Call(CE, State, LCtx); 245 PreVisitProcessArgs(C, Call, 246 "Function call argument is an uninitialized value", 247 BT_call_arg); 248 } 249} 250 251void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, 252 CheckerContext &C) const { 253 254 ProgramStateRef state = C.getState(); 255 const LocationContext *LCtx = C.getLocationContext(); 256 257 // FIXME: Handle 'super'? 258 if (const Expr *receiver = msg.getInstanceReceiver()) { 259 SVal recVal = state->getSVal(receiver, LCtx); 260 if (recVal.isUndef()) { 261 if (ExplodedNode *N = C.generateSink()) { 262 BugType *BT = 0; 263 if (msg.isPureMessageExpr()) { 264 if (!BT_msg_undef) 265 BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " 266 "is an uninitialized value")); 267 BT = BT_msg_undef.get(); 268 } 269 else { 270 if (!BT_objc_prop_undef) 271 BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " 272 "uninitialized object pointer")); 273 BT = BT_objc_prop_undef.get(); 274 } 275 BugReport *R = 276 new BugReport(*BT, BT->getName(), N); 277 R->addRange(receiver->getSourceRange()); 278 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 279 receiver, 280 R)); 281 C.EmitReport(R); 282 } 283 return; 284 } else { 285 // Bifurcate the state into nil and non-nil ones. 286 DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); 287 288 ProgramStateRef notNilState, nilState; 289 llvm::tie(notNilState, nilState) = state->assume(receiverVal); 290 291 // Handle receiver must be nil. 292 if (nilState && !notNilState) { 293 HandleNilReceiver(C, state, msg); 294 return; 295 } 296 } 297 } 298 299 const char *bugDesc = msg.isPropertySetter() ? 300 "Argument for property setter is an uninitialized value" 301 : "Argument in message expression is an uninitialized value"; 302 // Check for any arguments that are uninitialized/undefined. 303 PreVisitProcessArgs(C, ObjCMessageInvocation(msg, state, LCtx), 304 bugDesc, BT_msg_arg); 305} 306 307void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, 308 const ObjCMessage &msg, 309 ExplodedNode *N) const { 310 311 if (!BT_msg_ret) 312 BT_msg_ret.reset( 313 new BuiltinBug("Receiver in message expression is " 314 "'nil' and returns a garbage value")); 315 316 SmallString<200> buf; 317 llvm::raw_svector_ostream os(buf); 318 os << "The receiver of message '" << msg.getSelector().getAsString() 319 << "' is nil and returns a value of type '" 320 << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; 321 322 BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); 323 if (const Expr *receiver = msg.getInstanceReceiver()) { 324 report->addRange(receiver->getSourceRange()); 325 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 326 receiver, 327 report)); 328 } 329 C.EmitReport(report); 330} 331 332static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 333 return (triple.getVendor() == llvm::Triple::Apple && 334 (triple.getOS() == llvm::Triple::IOS || 335 !triple.isMacOSXVersionLT(10,5))); 336} 337 338void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 339 ProgramStateRef state, 340 ObjCMessage msg) const { 341 ASTContext &Ctx = C.getASTContext(); 342 343 // Check the return type of the message expression. A message to nil will 344 // return different values depending on the return type and the architecture. 345 QualType RetTy = msg.getType(Ctx); 346 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 347 const LocationContext *LCtx = C.getLocationContext(); 348 349 if (CanRetTy->isStructureOrClassType()) { 350 // Structure returns are safe since the compiler zeroes them out. 351 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 352 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 353 return; 354 } 355 356 // Other cases: check if sizeof(return type) > sizeof(void*) 357 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap() 358 .isConsumedExpr(msg.getMessageExpr())) { 359 // Compute: sizeof(void *) and sizeof(return type) 360 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 361 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 362 363 if (voidPtrSize < returnTypeSize && 364 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && 365 (Ctx.FloatTy == CanRetTy || 366 Ctx.DoubleTy == CanRetTy || 367 Ctx.LongDoubleTy == CanRetTy || 368 Ctx.LongLongTy == CanRetTy || 369 Ctx.UnsignedLongLongTy == CanRetTy))) { 370 if (ExplodedNode *N = C.generateSink(state)) 371 emitNilReceiverBug(C, msg, N); 372 return; 373 } 374 375 // Handle the safe cases where the return value is 0 if the 376 // receiver is nil. 377 // 378 // FIXME: For now take the conservative approach that we only 379 // return null values if we *know* that the receiver is nil. 380 // This is because we can have surprises like: 381 // 382 // ... = [[NSScreens screens] objectAtIndex:0]; 383 // 384 // What can happen is that [... screens] could return nil, but 385 // it most likely isn't nil. We should assume the semantics 386 // of this case unless we have *a lot* more knowledge. 387 // 388 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 389 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 390 return; 391 } 392 393 C.addTransition(state); 394} 395 396void ento::registerCallAndMessageChecker(CheckerManager &mgr) { 397 mgr.registerChecker<CallAndMessageChecker>(); 398} 399