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