CallAndMessageChecker.cpp revision cde8cdbd6a662c636164465ad309b5f17ff01064
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/Calls.h" 19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 21#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 22#include "clang/AST/ParentMap.h" 23#include "clang/Basic/TargetInfo.h" 24#include "llvm/ADT/SmallString.h" 25 26using namespace clang; 27using namespace ento; 28 29namespace { 30class CallAndMessageChecker 31 : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > { 32 mutable OwningPtr<BugType> BT_call_null; 33 mutable OwningPtr<BugType> BT_call_undef; 34 mutable OwningPtr<BugType> BT_call_arg; 35 mutable OwningPtr<BugType> BT_msg_undef; 36 mutable OwningPtr<BugType> BT_objc_prop_undef; 37 mutable OwningPtr<BugType> BT_msg_arg; 38 mutable OwningPtr<BugType> BT_msg_ret; 39public: 40 41 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 42 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; 43 44private: 45 static void PreVisitProcessArgs(CheckerContext &C, const CallEvent &Call, 46 const char *BT_desc, OwningPtr<BugType> &BT); 47 static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange, 48 const Expr *argEx, 49 const bool checkUninitFields, 50 const char *BT_desc, 51 OwningPtr<BugType> &BT); 52 53 static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); 54 void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, 55 ExplodedNode *N) const; 56 57 void HandleNilReceiver(CheckerContext &C, 58 ProgramStateRef state, 59 ObjCMessage msg) const; 60 61 static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) { 62 if (!BT) 63 BT.reset(new BuiltinBug(desc)); 64 } 65}; 66} // end anonymous namespace 67 68void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, 69 const CallExpr *CE) { 70 ExplodedNode *N = C.generateSink(); 71 if (!N) 72 return; 73 74 BugReport *R = new BugReport(*BT, BT->getName(), N); 75 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 76 bugreporter::GetCalleeExpr(N), R)); 77 C.EmitReport(R); 78} 79 80void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, 81 const CallEvent &Call, 82 const char *BT_desc, 83 OwningPtr<BugType> &BT) { 84 // Don't check for uninitialized field values in arguments if the 85 // caller has a body that is available and we have the chance to inline it. 86 // This is a hack, but is a reasonable compromise betweens sometimes warning 87 // and sometimes not depending on if we decide to inline a function. 88 const Decl *D = Call.getDecl(); 89 const bool checkUninitFields = 90 !(C.getAnalysisManager().shouldInlineCall() && 91 (D && D->getBody())); 92 93 for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) 94 if (PreVisitProcessArg(C, Call.getArgSVal(i), 95 Call.getArgSourceRange(i), Call.getArgExpr(i), 96 checkUninitFields, 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 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 // FIXME: ObjCMessage is set to be removed soon. 304 PreVisitProcessArgs(C, ObjCMessageSend(msg.getMessageExpr(), state, LCtx), 305 bugDesc, BT_msg_arg); 306} 307 308void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, 309 const ObjCMessage &msg, 310 ExplodedNode *N) const { 311 312 if (!BT_msg_ret) 313 BT_msg_ret.reset( 314 new BuiltinBug("Receiver in message expression is " 315 "'nil' and returns a garbage value")); 316 317 SmallString<200> buf; 318 llvm::raw_svector_ostream os(buf); 319 os << "The receiver of message '" << msg.getSelector().getAsString() 320 << "' is nil and returns a value of type '" 321 << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; 322 323 BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); 324 if (const Expr *receiver = msg.getInstanceReceiver()) { 325 report->addRange(receiver->getSourceRange()); 326 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 327 receiver, 328 report)); 329 } 330 C.EmitReport(report); 331} 332 333static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 334 return (triple.getVendor() == llvm::Triple::Apple && 335 (triple.getOS() == llvm::Triple::IOS || 336 !triple.isMacOSXVersionLT(10,5))); 337} 338 339void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 340 ProgramStateRef state, 341 ObjCMessage msg) const { 342 ASTContext &Ctx = C.getASTContext(); 343 344 // Check the return type of the message expression. A message to nil will 345 // return different values depending on the return type and the architecture. 346 QualType RetTy = msg.getType(Ctx); 347 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 348 const LocationContext *LCtx = C.getLocationContext(); 349 350 if (CanRetTy->isStructureOrClassType()) { 351 // Structure returns are safe since the compiler zeroes them out. 352 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 353 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 354 return; 355 } 356 357 // Other cases: check if sizeof(return type) > sizeof(void*) 358 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap() 359 .isConsumedExpr(msg.getMessageExpr())) { 360 // Compute: sizeof(void *) and sizeof(return type) 361 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 362 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 363 364 if (voidPtrSize < returnTypeSize && 365 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && 366 (Ctx.FloatTy == CanRetTy || 367 Ctx.DoubleTy == CanRetTy || 368 Ctx.LongDoubleTy == CanRetTy || 369 Ctx.LongLongTy == CanRetTy || 370 Ctx.UnsignedLongLongTy == CanRetTy))) { 371 if (ExplodedNode *N = C.generateSink(state)) 372 emitNilReceiverBug(C, msg, N); 373 return; 374 } 375 376 // Handle the safe cases where the return value is 0 if the 377 // receiver is nil. 378 // 379 // FIXME: For now take the conservative approach that we only 380 // return null values if we *know* that the receiver is nil. 381 // This is because we can have surprises like: 382 // 383 // ... = [[NSScreens screens] objectAtIndex:0]; 384 // 385 // What can happen is that [... screens] could return nil, but 386 // it most likely isn't nil. We should assume the semantics 387 // of this case unless we have *a lot* more knowledge. 388 // 389 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 390 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 391 return; 392 } 393 394 C.addTransition(state); 395} 396 397void ento::registerCallAndMessageChecker(CheckerManager &mgr) { 398 mgr.registerChecker<CallAndMessageChecker>(); 399} 400