clang API Documentation
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 }