CallAndMessageChecker.cpp revision 581deb3da481053c4993c7600f97acf7768caac5
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 25using namespace clang; 26using namespace ento; 27 28namespace { 29class 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; 38public: 39 40 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 41 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; 42 43private: 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 67void 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 79void 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 100bool 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 StoreManager &StoreMgr; 132 MemRegionManager &MrMgr; 133 Store store; 134 public: 135 FindUninitializedField(StoreManager &storeMgr, 136 MemRegionManager &mrMgr, Store s) 137 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} 138 139 bool Find(const TypedValueRegion *R) { 140 QualType T = R->getValueType(); 141 if (const RecordType *RT = T->getAsStructureType()) { 142 const RecordDecl *RD = RT->getDecl()->getDefinition(); 143 assert(RD && "Referred record has no definition"); 144 for (RecordDecl::field_iterator I = 145 RD->field_begin(), E = RD->field_end(); I!=E; ++I) { 146 const FieldRegion *FR = MrMgr.getFieldRegion(*I, R); 147 FieldChain.push_back(*I); 148 T = I->getType(); 149 if (T->getAsStructureType()) { 150 if (Find(FR)) 151 return true; 152 } 153 else { 154 const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR)); 155 if (V.isUndef()) 156 return true; 157 } 158 FieldChain.pop_back(); 159 } 160 } 161 162 return false; 163 } 164 }; 165 166 const LazyCompoundValData *D = LV->getCVData(); 167 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(), 168 C.getSValBuilder().getRegionManager(), 169 D->getStore()); 170 171 if (F.Find(D->getRegion())) { 172 if (ExplodedNode *N = C.generateSink()) { 173 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 const LocationContext *LCtx = C.getLocationContext(); 214 SVal L = C.getState()->getSVal(Callee, LCtx); 215 216 if (L.isUndef()) { 217 if (!BT_call_undef) 218 BT_call_undef.reset(new BuiltinBug("Called function pointer is an " 219 "uninitalized pointer value")); 220 EmitBadCall(BT_call_undef.get(), C, CE); 221 return; 222 } 223 224 if (isa<loc::ConcreteInt>(L)) { 225 if (!BT_call_null) 226 BT_call_null.reset( 227 new BuiltinBug("Called function pointer is null (null dereference)")); 228 EmitBadCall(BT_call_null.get(), C, CE); 229 } 230 231 PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx), 232 "Function call argument is an uninitialized value", 233 BT_call_arg); 234} 235 236void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, 237 CheckerContext &C) const { 238 239 ProgramStateRef state = C.getState(); 240 const LocationContext *LCtx = C.getLocationContext(); 241 242 // FIXME: Handle 'super'? 243 if (const Expr *receiver = msg.getInstanceReceiver()) { 244 SVal recVal = state->getSVal(receiver, LCtx); 245 if (recVal.isUndef()) { 246 if (ExplodedNode *N = C.generateSink()) { 247 BugType *BT = 0; 248 if (msg.isPureMessageExpr()) { 249 if (!BT_msg_undef) 250 BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " 251 "is an uninitialized value")); 252 BT = BT_msg_undef.get(); 253 } 254 else { 255 if (!BT_objc_prop_undef) 256 BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " 257 "uninitialized object pointer")); 258 BT = BT_objc_prop_undef.get(); 259 } 260 BugReport *R = 261 new BugReport(*BT, BT->getName(), N); 262 R->addRange(receiver->getSourceRange()); 263 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 264 receiver, 265 R)); 266 C.EmitReport(R); 267 } 268 return; 269 } else { 270 // Bifurcate the state into nil and non-nil ones. 271 DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); 272 273 ProgramStateRef notNilState, nilState; 274 llvm::tie(notNilState, nilState) = state->assume(receiverVal); 275 276 // Handle receiver must be nil. 277 if (nilState && !notNilState) { 278 HandleNilReceiver(C, state, msg); 279 return; 280 } 281 } 282 } 283 284 const char *bugDesc = msg.isPropertySetter() ? 285 "Argument for property setter is an uninitialized value" 286 : "Argument in message expression is an uninitialized value"; 287 // Check for any arguments that are uninitialized/undefined. 288 PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx), 289 bugDesc, BT_msg_arg); 290} 291 292void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, 293 const ObjCMessage &msg, 294 ExplodedNode *N) const { 295 296 if (!BT_msg_ret) 297 BT_msg_ret.reset( 298 new BuiltinBug("Receiver in message expression is " 299 "'nil' and returns a garbage value")); 300 301 SmallString<200> buf; 302 llvm::raw_svector_ostream os(buf); 303 os << "The receiver of message '" << msg.getSelector().getAsString() 304 << "' is nil and returns a value of type '" 305 << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; 306 307 BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); 308 if (const Expr *receiver = msg.getInstanceReceiver()) { 309 report->addRange(receiver->getSourceRange()); 310 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 311 receiver, 312 report)); 313 } 314 C.EmitReport(report); 315} 316 317static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 318 return (triple.getVendor() == llvm::Triple::Apple && 319 (triple.getOS() == llvm::Triple::IOS || 320 !triple.isMacOSXVersionLT(10,5))); 321} 322 323void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 324 ProgramStateRef state, 325 ObjCMessage msg) const { 326 ASTContext &Ctx = C.getASTContext(); 327 328 // Check the return type of the message expression. A message to nil will 329 // return different values depending on the return type and the architecture. 330 QualType RetTy = msg.getType(Ctx); 331 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 332 const LocationContext *LCtx = C.getLocationContext(); 333 334 if (CanRetTy->isStructureOrClassType()) { 335 // Structure returns are safe since the compiler zeroes them out. 336 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 337 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 338 return; 339 } 340 341 // Other cases: check if sizeof(return type) > sizeof(void*) 342 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap() 343 .isConsumedExpr(msg.getMessageExpr())) { 344 // Compute: sizeof(void *) and sizeof(return type) 345 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 346 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 347 348 if (voidPtrSize < returnTypeSize && 349 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && 350 (Ctx.FloatTy == CanRetTy || 351 Ctx.DoubleTy == CanRetTy || 352 Ctx.LongDoubleTy == CanRetTy || 353 Ctx.LongLongTy == CanRetTy || 354 Ctx.UnsignedLongLongTy == CanRetTy))) { 355 if (ExplodedNode *N = C.generateSink(state)) 356 emitNilReceiverBug(C, msg, N); 357 return; 358 } 359 360 // Handle the safe cases where the return value is 0 if the 361 // receiver is nil. 362 // 363 // FIXME: For now take the conservative approach that we only 364 // return null values if we *know* that the receiver is nil. 365 // This is because we can have surprises like: 366 // 367 // ... = [[NSScreens screens] objectAtIndex:0]; 368 // 369 // What can happen is that [... screens] could return nil, but 370 // it most likely isn't nil. We should assume the semantics 371 // of this case unless we have *a lot* more knowledge. 372 // 373 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 374 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 375 return; 376 } 377 378 C.addTransition(state); 379} 380 381void ento::registerCallAndMessageChecker(CheckerManager &mgr) { 382 mgr.registerChecker<CallAndMessageChecker>(); 383} 384