CallAndMessageChecker.cpp revision 9697934650354bed2e509d8e7e44f21a1fb00f76
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/BugReporter/BugType.h" 20#include "clang/AST/ParentMap.h" 21#include "clang/Basic/TargetInfo.h" 22 23using namespace clang; 24using namespace ento; 25 26namespace { 27class CallAndMessageChecker 28 : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > { 29 mutable llvm::OwningPtr<BugType> BT_call_null; 30 mutable llvm::OwningPtr<BugType> BT_call_undef; 31 mutable llvm::OwningPtr<BugType> BT_call_arg; 32 mutable llvm::OwningPtr<BugType> BT_msg_undef; 33 mutable llvm::OwningPtr<BugType> BT_msg_arg; 34 mutable llvm::OwningPtr<BugType> BT_msg_ret; 35public: 36 37 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 38 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; 39 40private: 41 static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg, 42 const char *BT_desc, llvm::OwningPtr<BugType> &BT); 43 static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange, 44 const Expr *argEx, const char *BT_desc, llvm::OwningPtr<BugType> &BT); 45 46 static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); 47 void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, 48 ExplodedNode *N) const; 49 50 void HandleNilReceiver(CheckerContext &C, const GRState *state, 51 ObjCMessage msg) const; 52 53 static void LazyInit_BT(const char *desc, llvm::OwningPtr<BugType> &BT) { 54 if (!BT) 55 BT.reset(new BuiltinBug(desc)); 56 } 57}; 58} // end anonymous namespace 59 60void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, 61 const CallExpr *CE) { 62 ExplodedNode *N = C.generateSink(); 63 if (!N) 64 return; 65 66 EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); 67 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 68 bugreporter::GetCalleeExpr(N)); 69 C.EmitReport(R); 70} 71 72void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, 73 CallOrObjCMessage callOrMsg, 74 const char *BT_desc, 75 llvm::OwningPtr<BugType> &BT) { 76 for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) 77 if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), 78 callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), 79 BT_desc, BT)) 80 return; 81} 82 83bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, 84 SVal V, SourceRange argRange, 85 const Expr *argEx, 86 const char *BT_desc, 87 llvm::OwningPtr<BugType> &BT) { 88 89 if (V.isUndef()) { 90 if (ExplodedNode *N = C.generateSink()) { 91 LazyInit_BT(BT_desc, BT); 92 93 // Generate a report for this bug. 94 EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); 95 R->addRange(argRange); 96 if (argEx) 97 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx); 98 C.EmitReport(R); 99 } 100 return true; 101 } 102 103 if (const nonloc::LazyCompoundVal *LV = 104 dyn_cast<nonloc::LazyCompoundVal>(&V)) { 105 106 class FindUninitializedField { 107 public: 108 SmallVector<const FieldDecl *, 10> FieldChain; 109 private: 110 ASTContext &C; 111 StoreManager &StoreMgr; 112 MemRegionManager &MrMgr; 113 Store store; 114 public: 115 FindUninitializedField(ASTContext &c, StoreManager &storeMgr, 116 MemRegionManager &mrMgr, Store s) 117 : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} 118 119 bool Find(const TypedValueRegion *R) { 120 QualType T = R->getValueType(); 121 if (const RecordType *RT = T->getAsStructureType()) { 122 const RecordDecl *RD = RT->getDecl()->getDefinition(); 123 assert(RD && "Referred record has no definition"); 124 for (RecordDecl::field_iterator I = 125 RD->field_begin(), E = RD->field_end(); I!=E; ++I) { 126 const FieldRegion *FR = MrMgr.getFieldRegion(*I, R); 127 FieldChain.push_back(*I); 128 T = (*I)->getType(); 129 if (T->getAsStructureType()) { 130 if (Find(FR)) 131 return true; 132 } 133 else { 134 const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR)); 135 if (V.isUndef()) 136 return true; 137 } 138 FieldChain.pop_back(); 139 } 140 } 141 142 return false; 143 } 144 }; 145 146 const LazyCompoundValData *D = LV->getCVData(); 147 FindUninitializedField F(C.getASTContext(), 148 C.getState()->getStateManager().getStoreManager(), 149 C.getSValBuilder().getRegionManager(), 150 D->getStore()); 151 152 if (F.Find(D->getRegion())) { 153 if (ExplodedNode *N = C.generateSink()) { 154 LazyInit_BT(BT_desc, BT); 155 llvm::SmallString<512> Str; 156 llvm::raw_svector_ostream os(Str); 157 os << "Passed-by-value struct argument contains uninitialized data"; 158 159 if (F.FieldChain.size() == 1) 160 os << " (e.g., field: '" << F.FieldChain[0] << "')"; 161 else { 162 os << " (e.g., via the field chain: '"; 163 bool first = true; 164 for (SmallVectorImpl<const FieldDecl *>::iterator 165 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ 166 if (first) 167 first = false; 168 else 169 os << '.'; 170 os << *DI; 171 } 172 os << "')"; 173 } 174 175 // Generate a report for this bug. 176 EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); 177 R->addRange(argRange); 178 179 // FIXME: enhance track back for uninitialized value for arbitrary 180 // memregions 181 C.EmitReport(R); 182 } 183 return true; 184 } 185 } 186 187 return false; 188} 189 190void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, 191 CheckerContext &C) const{ 192 193 const Expr *Callee = CE->getCallee()->IgnoreParens(); 194 SVal L = C.getState()->getSVal(Callee); 195 196 if (L.isUndef()) { 197 if (!BT_call_undef) 198 BT_call_undef.reset(new BuiltinBug("Called function pointer is an " 199 "uninitalized pointer value")); 200 EmitBadCall(BT_call_undef.get(), C, CE); 201 return; 202 } 203 204 if (isa<loc::ConcreteInt>(L)) { 205 if (!BT_call_null) 206 BT_call_null.reset( 207 new BuiltinBug("Called function pointer is null (null dereference)")); 208 EmitBadCall(BT_call_null.get(), C, CE); 209 } 210 211 PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()), 212 "Function call argument is an uninitialized value", 213 BT_call_arg); 214} 215 216void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, 217 CheckerContext &C) const { 218 219 const GRState *state = C.getState(); 220 221 // FIXME: Handle 'super'? 222 if (const Expr *receiver = msg.getInstanceReceiver()) { 223 SVal recVal = state->getSVal(receiver); 224 if (recVal.isUndef()) { 225 if (ExplodedNode *N = C.generateSink()) { 226 if (!BT_msg_undef) 227 BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is " 228 "an uninitialized value")); 229 EnhancedBugReport *R = 230 new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N); 231 R->addRange(receiver->getSourceRange()); 232 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 233 receiver); 234 C.EmitReport(R); 235 } 236 return; 237 } else { 238 // Bifurcate the state into nil and non-nil ones. 239 DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); 240 241 const GRState *notNilState, *nilState; 242 llvm::tie(notNilState, nilState) = state->assume(receiverVal); 243 244 // Handle receiver must be nil. 245 if (nilState && !notNilState) { 246 HandleNilReceiver(C, state, msg); 247 return; 248 } 249 } 250 } 251 252 const char *bugDesc = msg.isPropertySetter() ? 253 "Argument for property setter is an uninitialized value" 254 : "Argument in message expression is an uninitialized value"; 255 // Check for any arguments that are uninitialized/undefined. 256 PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg); 257} 258 259void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, 260 const ObjCMessage &msg, 261 ExplodedNode *N) const { 262 263 if (!BT_msg_ret) 264 BT_msg_ret.reset( 265 new BuiltinBug("Receiver in message expression is " 266 "'nil' and returns a garbage value")); 267 268 llvm::SmallString<200> buf; 269 llvm::raw_svector_ostream os(buf); 270 os << "The receiver of message '" << msg.getSelector().getAsString() 271 << "' is nil and returns a value of type '" 272 << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; 273 274 EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); 275 if (const Expr *receiver = msg.getInstanceReceiver()) { 276 report->addRange(receiver->getSourceRange()); 277 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 278 receiver); 279 } 280 C.EmitReport(report); 281} 282 283static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 284 return triple.getVendor() == llvm::Triple::Apple && 285 (!triple.isMacOSXVersionLT(10,5) || 286 triple.getArch() == llvm::Triple::arm || 287 triple.getArch() == llvm::Triple::thumb); 288} 289 290void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 291 const GRState *state, 292 ObjCMessage msg) const { 293 ASTContext &Ctx = C.getASTContext(); 294 295 // Check the return type of the message expression. A message to nil will 296 // return different values depending on the return type and the architecture. 297 QualType RetTy = msg.getType(Ctx); 298 299 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 300 301 if (CanRetTy->isStructureOrClassType()) { 302 // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead 303 // have the "use of undefined value" be smarter about where the 304 // undefined value came from. 305 if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){ 306 if (ExplodedNode* N = C.generateSink(state)) 307 emitNilReceiverBug(C, msg, N); 308 return; 309 } 310 311 // The result is not consumed by a surrounding expression. Just propagate 312 // the current state. 313 C.addTransition(state); 314 return; 315 } 316 317 // Other cases: check if the return type is smaller than void*. 318 if (CanRetTy != Ctx.VoidTy && 319 C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) { 320 // Compute: sizeof(void *) and sizeof(return type) 321 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 322 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 323 324 if (voidPtrSize < returnTypeSize && 325 !(supportsNilWithFloatRet(Ctx.Target.getTriple()) && 326 (Ctx.FloatTy == CanRetTy || 327 Ctx.DoubleTy == CanRetTy || 328 Ctx.LongDoubleTy == CanRetTy || 329 Ctx.LongLongTy == CanRetTy || 330 Ctx.UnsignedLongLongTy == CanRetTy))) { 331 if (ExplodedNode* N = C.generateSink(state)) 332 emitNilReceiverBug(C, msg, N); 333 return; 334 } 335 336 // Handle the safe cases where the return value is 0 if the 337 // receiver is nil. 338 // 339 // FIXME: For now take the conservative approach that we only 340 // return null values if we *know* that the receiver is nil. 341 // This is because we can have surprises like: 342 // 343 // ... = [[NSScreens screens] objectAtIndex:0]; 344 // 345 // What can happen is that [... screens] could return nil, but 346 // it most likely isn't nil. We should assume the semantics 347 // of this case unless we have *a lot* more knowledge. 348 // 349 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); 350 C.generateNode(state->BindExpr(msg.getOriginExpr(), V)); 351 return; 352 } 353 354 C.addTransition(state); 355} 356 357void ento::registerCallAndMessageChecker(CheckerManager &mgr) { 358 mgr.registerChecker<CallAndMessageChecker>(); 359} 360