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