CallAndMessageChecker.cpp revision e4d653b5a4cba281502177f6ef03d43e3ebb2b6a
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))); 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 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 ASTContext &C; 131 StoreManager &StoreMgr; 132 MemRegionManager &MrMgr; 133 Store store; 134 public: 135 FindUninitializedField(ASTContext &c, StoreManager &storeMgr, 136 MemRegionManager &mrMgr, Store s) 137 : C(c), 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.getASTContext(), 168 C.getState()->getStateManager().getStoreManager(), 169 C.getSValBuilder().getRegionManager(), 170 D->getStore()); 171 172 if (F.Find(D->getRegion())) { 173 if (ExplodedNode *N = C.generateSink()) { 174 LazyInit_BT(BT_desc, BT); 175 SmallString<512> Str; 176 llvm::raw_svector_ostream os(Str); 177 os << "Passed-by-value struct argument contains uninitialized data"; 178 179 if (F.FieldChain.size() == 1) 180 os << " (e.g., field: '" << *F.FieldChain[0] << "')"; 181 else { 182 os << " (e.g., via the field chain: '"; 183 bool first = true; 184 for (SmallVectorImpl<const FieldDecl *>::iterator 185 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ 186 if (first) 187 first = false; 188 else 189 os << '.'; 190 os << **DI; 191 } 192 os << "')"; 193 } 194 195 // Generate a report for this bug. 196 BugReport *R = new BugReport(*BT, os.str(), N); 197 R->addRange(argRange); 198 199 // FIXME: enhance track back for uninitialized value for arbitrary 200 // memregions 201 C.EmitReport(R); 202 } 203 return true; 204 } 205 } 206 207 return false; 208} 209 210void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, 211 CheckerContext &C) const{ 212 213 const Expr *Callee = CE->getCallee()->IgnoreParens(); 214 const LocationContext *LCtx = C.getLocationContext(); 215 SVal L = C.getState()->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 (isa<loc::ConcreteInt>(L)) { 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 PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx), 233 "Function call argument is an uninitialized value", 234 BT_call_arg); 235} 236 237void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, 238 CheckerContext &C) const { 239 240 ProgramStateRef state = C.getState(); 241 const LocationContext *LCtx = C.getLocationContext(); 242 243 // FIXME: Handle 'super'? 244 if (const Expr *receiver = msg.getInstanceReceiver()) { 245 SVal recVal = state->getSVal(receiver, LCtx); 246 if (recVal.isUndef()) { 247 if (ExplodedNode *N = C.generateSink()) { 248 BugType *BT = 0; 249 if (msg.isPureMessageExpr()) { 250 if (!BT_msg_undef) 251 BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " 252 "is an uninitialized value")); 253 BT = BT_msg_undef.get(); 254 } 255 else { 256 if (!BT_objc_prop_undef) 257 BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " 258 "uninitialized object pointer")); 259 BT = BT_objc_prop_undef.get(); 260 } 261 BugReport *R = 262 new BugReport(*BT, BT->getName(), N); 263 R->addRange(receiver->getSourceRange()); 264 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 265 receiver)); 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 } 313 C.EmitReport(report); 314} 315 316static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 317 return (triple.getVendor() == llvm::Triple::Apple && 318 (triple.getOS() == llvm::Triple::IOS || 319 !triple.isMacOSXVersionLT(10,5))); 320} 321 322void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 323 ProgramStateRef state, 324 ObjCMessage msg) const { 325 ASTContext &Ctx = C.getASTContext(); 326 327 // Check the return type of the message expression. A message to nil will 328 // return different values depending on the return type and the architecture. 329 QualType RetTy = msg.getType(Ctx); 330 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 331 const LocationContext *LCtx = C.getLocationContext(); 332 333 if (CanRetTy->isStructureOrClassType()) { 334 // Structure returns are safe since the compiler zeroes them out. 335 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 336 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 337 return; 338 } 339 340 // Other cases: check if sizeof(return type) > sizeof(void*) 341 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap() 342 .isConsumedExpr(msg.getMessageExpr())) { 343 // Compute: sizeof(void *) and sizeof(return type) 344 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 345 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 346 347 if (voidPtrSize < returnTypeSize && 348 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && 349 (Ctx.FloatTy == CanRetTy || 350 Ctx.DoubleTy == CanRetTy || 351 Ctx.LongDoubleTy == CanRetTy || 352 Ctx.LongLongTy == CanRetTy || 353 Ctx.UnsignedLongLongTy == CanRetTy))) { 354 if (ExplodedNode *N = C.generateSink(state)) 355 emitNilReceiverBug(C, msg, N); 356 return; 357 } 358 359 // Handle the safe cases where the return value is 0 if the 360 // receiver is nil. 361 // 362 // FIXME: For now take the conservative approach that we only 363 // return null values if we *know* that the receiver is nil. 364 // This is because we can have surprises like: 365 // 366 // ... = [[NSScreens screens] objectAtIndex:0]; 367 // 368 // What can happen is that [... screens] could return nil, but 369 // it most likely isn't nil. We should assume the semantics 370 // of this case unless we have *a lot* more knowledge. 371 // 372 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 373 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V)); 374 return; 375 } 376 377 C.addTransition(state); 378} 379 380void ento::registerCallAndMessageChecker(CheckerManager &mgr) { 381 mgr.registerChecker<CallAndMessageChecker>(); 382} 383