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