CallAndMessageChecker.cpp revision de507eaf3cb54d3cb234dc14499c10ab3373d15f
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/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(const ObjCMethodCall &msg, CheckerContext &C) const; 42 43private: 44 static void PreVisitProcessArgs(CheckerContext &C, const CallEvent &Call, 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 ObjCMethodCall &msg, 54 ExplodedNode *N) const; 55 56 void HandleNilReceiver(CheckerContext &C, 57 ProgramStateRef state, 58 const ObjCMethodCall &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 const CallEvent &Call, 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 = Call.getDecl(); 88 const bool checkUninitFields = 89 !(C.getAnalysisManager().shouldInlineCall() && 90 (D && D->getBody())); 91 92 for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) 93 if (PreVisitProcessArg(C, Call.getArgSVal(i), 94 Call.getArgSourceRange(i), Call.getArgExpr(i), 95 checkUninitFields, BT_desc, BT)) 96 return; 97} 98 99bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, 100 SVal V, SourceRange argRange, 101 const Expr *argEx, 102 const bool checkUninitFields, 103 const char *BT_desc, 104 OwningPtr<BugType> &BT) { 105 if (V.isUndef()) { 106 if (ExplodedNode *N = C.generateSink()) { 107 LazyInit_BT(BT_desc, BT); 108 109 // Generate a report for this bug. 110 BugReport *R = new BugReport(*BT, BT->getName(), N); 111 R->addRange(argRange); 112 if (argEx) 113 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx, 114 R)); 115 C.EmitReport(R); 116 } 117 return true; 118 } 119 120 if (!checkUninitFields) 121 return false; 122 123 if (const nonloc::LazyCompoundVal *LV = 124 dyn_cast<nonloc::LazyCompoundVal>(&V)) { 125 126 class FindUninitializedField { 127 public: 128 SmallVector<const FieldDecl *, 10> FieldChain; 129 private: 130 StoreManager &StoreMgr; 131 MemRegionManager &MrMgr; 132 Store store; 133 public: 134 FindUninitializedField(StoreManager &storeMgr, 135 MemRegionManager &mrMgr, Store s) 136 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} 137 138 bool Find(const TypedValueRegion *R) { 139 QualType T = R->getValueType(); 140 if (const RecordType *RT = T->getAsStructureType()) { 141 const RecordDecl *RD = RT->getDecl()->getDefinition(); 142 assert(RD && "Referred record has no definition"); 143 for (RecordDecl::field_iterator I = 144 RD->field_begin(), E = RD->field_end(); I!=E; ++I) { 145 const FieldRegion *FR = MrMgr.getFieldRegion(*I, R); 146 FieldChain.push_back(*I); 147 T = I->getType(); 148 if (T->getAsStructureType()) { 149 if (Find(FR)) 150 return true; 151 } 152 else { 153 const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR)); 154 if (V.isUndef()) 155 return true; 156 } 157 FieldChain.pop_back(); 158 } 159 } 160 161 return false; 162 } 163 }; 164 165 const LazyCompoundValData *D = LV->getCVData(); 166 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(), 167 C.getSValBuilder().getRegionManager(), 168 D->getStore()); 169 170 if (F.Find(D->getRegion())) { 171 if (ExplodedNode *N = C.generateSink()) { 172 LazyInit_BT(BT_desc, BT); 173 SmallString<512> Str; 174 llvm::raw_svector_ostream os(Str); 175 os << "Passed-by-value struct argument contains uninitialized data"; 176 177 if (F.FieldChain.size() == 1) 178 os << " (e.g., field: '" << *F.FieldChain[0] << "')"; 179 else { 180 os << " (e.g., via the field chain: '"; 181 bool first = true; 182 for (SmallVectorImpl<const FieldDecl *>::iterator 183 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ 184 if (first) 185 first = false; 186 else 187 os << '.'; 188 os << **DI; 189 } 190 os << "')"; 191 } 192 193 // Generate a report for this bug. 194 BugReport *R = new BugReport(*BT, os.str(), N); 195 R->addRange(argRange); 196 197 // FIXME: enhance track back for uninitialized value for arbitrary 198 // memregions 199 C.EmitReport(R); 200 } 201 return true; 202 } 203 } 204 205 return false; 206} 207 208void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, 209 CheckerContext &C) const{ 210 211 const Expr *Callee = CE->getCallee()->IgnoreParens(); 212 ProgramStateRef State = C.getState(); 213 const LocationContext *LCtx = C.getLocationContext(); 214 SVal L = State->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 (L.isZeroConstant()) { 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 // FIXME: This tree of switching can go away if/when we add a check::postCall. 232 if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { 233 BlockCall Call(CE, State, LCtx); 234 PreVisitProcessArgs(C, Call, 235 "Block call argument is an uninitialized value", 236 BT_call_arg); 237 } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) { 238 CXXMemberCall Call(me, State, LCtx); 239 PreVisitProcessArgs(C, Call, 240 "Function call argument is an uninitialized value", 241 BT_call_arg); 242 } else { 243 FunctionCall Call(CE, State, LCtx); 244 PreVisitProcessArgs(C, Call, 245 "Function call argument is an uninitialized value", 246 BT_call_arg); 247 } 248} 249 250void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 251 CheckerContext &C) const { 252 SVal recVal = msg.getReceiverSVal(); 253 if (recVal.isUndef()) { 254 if (ExplodedNode *N = C.generateSink()) { 255 BugType *BT = 0; 256 if (isa<ObjCPropertyAccess>(msg)) { 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 } else { 262 if (!BT_msg_undef) 263 BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " 264 "is an uninitialized value")); 265 BT = BT_msg_undef.get(); 266 } 267 BugReport *R = new BugReport(*BT, BT->getName(), N); 268 R->addRange(msg.getReceiverSourceRange()); 269 270 // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet. 271 if (const Expr *ReceiverE = msg.getInstanceReceiverExpr()) 272 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 273 ReceiverE, 274 R)); 275 C.EmitReport(R); 276 } 277 return; 278 } else { 279 // Bifurcate the state into nil and non-nil ones. 280 DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); 281 282 ProgramStateRef state = C.getState(); 283 ProgramStateRef notNilState, nilState; 284 llvm::tie(notNilState, nilState) = state->assume(receiverVal); 285 286 // Handle receiver must be nil. 287 if (nilState && !notNilState) { 288 HandleNilReceiver(C, state, msg); 289 return; 290 } 291 } 292 293 const char *bugDesc = "Argument in message expression is an " 294 "uninitialized value"; 295 if (const ObjCPropertyAccess *Prop = dyn_cast<ObjCPropertyAccess>(&msg)) 296 if (Prop->isSetter()) 297 bugDesc = "Argument for property setter is an uninitialized value"; 298 299 // Check for any arguments that are uninitialized/undefined. 300 PreVisitProcessArgs(C, msg, bugDesc, BT_msg_arg); 301} 302 303void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, 304 const ObjCMethodCall &msg, 305 ExplodedNode *N) const { 306 307 if (!BT_msg_ret) 308 BT_msg_ret.reset( 309 new BuiltinBug("Receiver in message expression is " 310 "'nil' and returns a garbage value")); 311 312 SmallString<200> buf; 313 llvm::raw_svector_ostream os(buf); 314 os << "The receiver of message '" << msg.getSelector().getAsString() 315 << "' is nil and returns a value of type '"; 316 msg.getResultType().print(os, C.getLangOpts()); 317 os << "' that will be garbage"; 318 319 BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); 320 // FIXME: This won't track "self" in messages to super. 321 if (const Expr *receiver = msg.getInstanceReceiverExpr()) { 322 report->addRange(receiver->getSourceRange()); 323 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 324 receiver, 325 report)); 326 } 327 C.EmitReport(report); 328} 329 330static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 331 return (triple.getVendor() == llvm::Triple::Apple && 332 (triple.getOS() == llvm::Triple::IOS || 333 !triple.isMacOSXVersionLT(10,5))); 334} 335 336void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 337 ProgramStateRef state, 338 const ObjCMethodCall &Msg) const { 339 ASTContext &Ctx = C.getASTContext(); 340 341 // Check the return type of the message expression. A message to nil will 342 // return different values depending on the return type and the architecture. 343 QualType RetTy = Msg.getResultType(); 344 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 345 const LocationContext *LCtx = C.getLocationContext(); 346 347 if (CanRetTy->isStructureOrClassType()) { 348 // Structure returns are safe since the compiler zeroes them out. 349 SVal V = C.getSValBuilder().makeZeroVal(RetTy); 350 C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V)); 351 return; 352 } 353 354 // Other cases: check if sizeof(return type) > sizeof(void*) 355 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap() 356 .isConsumedExpr(Msg.getOriginExpr())) { 357 // Compute: sizeof(void *) and sizeof(return type) 358 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 359 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 360 361 if (voidPtrSize < returnTypeSize && 362 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && 363 (Ctx.FloatTy == CanRetTy || 364 Ctx.DoubleTy == CanRetTy || 365 Ctx.LongDoubleTy == CanRetTy || 366 Ctx.LongLongTy == CanRetTy || 367 Ctx.UnsignedLongLongTy == CanRetTy))) { 368 if (ExplodedNode *N = C.generateSink(state)) 369 emitNilReceiverBug(C, Msg, N); 370 return; 371 } 372 373 // Handle the safe cases where the return value is 0 if the 374 // receiver is nil. 375 // 376 // FIXME: For now take the conservative approach that we only 377 // return null values if we *know* that the receiver is nil. 378 // This is because we can have surprises like: 379 // 380 // ... = [[NSScreens screens] objectAtIndex:0]; 381 // 382 // What can happen is that [... screens] could return nil, but 383 // it most likely isn't nil. We should assume the semantics 384 // of this case unless we have *a lot* more knowledge. 385 // 386 SVal V = C.getSValBuilder().makeZeroVal(RetTy); 387 C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V)); 388 return; 389 } 390 391 C.addTransition(state); 392} 393 394void ento::registerCallAndMessageChecker(CheckerManager &mgr) { 395 mgr.registerChecker<CallAndMessageChecker>(); 396} 397