1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This defines CallAndMessageChecker, a builtin checker that checks for various
11 // errors of call and objc message expressions.
13 //===----------------------------------------------------------------------===//
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"
25 using namespace clang;
29 class 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;
40 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
41 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
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,
48 const bool checkUninitFields,
50 OwningPtr<BugType> &BT);
52 static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
53 void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
54 ExplodedNode *N) const;
56 void HandleNilReceiver(CheckerContext &C,
57 ProgramStateRef state,
58 ObjCMessage msg) const;
60 static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
62 BT.reset(new BuiltinBug(desc));
65 } // end anonymous namespace
67 void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
69 ExplodedNode *N = C.generateSink();
73 BugReport *R = new BugReport(*BT, BT->getName(), N);
74 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
75 bugreporter::GetCalleeExpr(N), R));
79 void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
80 CallOrObjCMessage callOrMsg,
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() &&
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),
100 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
101 SVal V, SourceRange argRange,
103 const bool checkUninitFields,
105 OwningPtr<BugType> &BT) {
107 if (ExplodedNode *N = C.generateSink()) {
108 LazyInit_BT(BT_desc, BT);
110 // Generate a report for this bug.
111 BugReport *R = new BugReport(*BT, BT->getName(), N);
112 R->addRange(argRange);
114 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx,
121 if (!checkUninitFields)
124 if (const nonloc::LazyCompoundVal *LV =
125 dyn_cast<nonloc::LazyCompoundVal>(&V)) {
127 class FindUninitializedField {
129 SmallVector<const FieldDecl *, 10> FieldChain;
132 StoreManager &StoreMgr;
133 MemRegionManager &MrMgr;
136 FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
137 MemRegionManager &mrMgr, Store s)
138 : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
140 bool Find(const TypedValueRegion *R) {
141 QualType T = R->getValueType();
142 if (const RecordType *RT = T->getAsStructureType()) {
143 const RecordDecl *RD = RT->getDecl()->getDefinition();
144 assert(RD && "Referred record has no definition");
145 for (RecordDecl::field_iterator I =
146 RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
147 const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
148 FieldChain.push_back(*I);
150 if (T->getAsStructureType()) {
155 const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
159 FieldChain.pop_back();
167 const LazyCompoundValData *D = LV->getCVData();
168 FindUninitializedField F(C.getASTContext(),
169 C.getState()->getStateManager().getStoreManager(),
170 C.getSValBuilder().getRegionManager(),
173 if (F.Find(D->getRegion())) {
174 if (ExplodedNode *N = C.generateSink()) {
175 LazyInit_BT(BT_desc, BT);
176 SmallString<512> Str;
177 llvm::raw_svector_ostream os(Str);
178 os << "Passed-by-value struct argument contains uninitialized data";
180 if (F.FieldChain.size() == 1)
181 os << " (e.g., field: '" << *F.FieldChain[0] << "')";
183 os << " (e.g., via the field chain: '";
185 for (SmallVectorImpl<const FieldDecl *>::iterator
186 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
196 // Generate a report for this bug.
197 BugReport *R = new BugReport(*BT, os.str(), N);
198 R->addRange(argRange);
200 // FIXME: enhance track back for uninitialized value for arbitrary
211 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
212 CheckerContext &C) const{
214 const Expr *Callee = CE->getCallee()->IgnoreParens();
215 const LocationContext *LCtx = C.getLocationContext();
216 SVal L = C.getState()->getSVal(Callee, LCtx);
220 BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
221 "uninitalized pointer value"));
222 EmitBadCall(BT_call_undef.get(), C, CE);
226 if (isa<loc::ConcreteInt>(L)) {
229 new BuiltinBug("Called function pointer is null (null dereference)"));
230 EmitBadCall(BT_call_null.get(), C, CE);
233 PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
234 "Function call argument is an uninitialized value",
238 void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
239 CheckerContext &C) const {
241 ProgramStateRef state = C.getState();
242 const LocationContext *LCtx = C.getLocationContext();
244 // FIXME: Handle 'super'?
245 if (const Expr *receiver = msg.getInstanceReceiver()) {
246 SVal recVal = state->getSVal(receiver, LCtx);
247 if (recVal.isUndef()) {
248 if (ExplodedNode *N = C.generateSink()) {
250 if (msg.isPureMessageExpr()) {
252 BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
253 "is an uninitialized value"));
254 BT = BT_msg_undef.get();
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();
263 new BugReport(*BT, BT->getName(), N);
264 R->addRange(receiver->getSourceRange());
265 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
272 // Bifurcate the state into nil and non-nil ones.
273 DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
275 ProgramStateRef notNilState, nilState;
276 llvm::tie(notNilState, nilState) = state->assume(receiverVal);
278 // Handle receiver must be nil.
279 if (nilState && !notNilState) {
280 HandleNilReceiver(C, state, msg);
286 const char *bugDesc = msg.isPropertySetter() ?
287 "Argument for property setter is an uninitialized value"
288 : "Argument in message expression is an uninitialized value";
289 // Check for any arguments that are uninitialized/undefined.
290 PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
291 bugDesc, BT_msg_arg);
294 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
295 const ObjCMessage &msg,
296 ExplodedNode *N) const {
300 new BuiltinBug("Receiver in message expression is "
301 "'nil' and returns a garbage value"));
303 SmallString<200> buf;
304 llvm::raw_svector_ostream os(buf);
305 os << "The receiver of message '" << msg.getSelector().getAsString()
306 << "' is nil and returns a value of type '"
307 << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
309 BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
310 if (const Expr *receiver = msg.getInstanceReceiver()) {
311 report->addRange(receiver->getSourceRange());
312 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
316 C.EmitReport(report);
319 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
320 return (triple.getVendor() == llvm::Triple::Apple &&
321 (triple.getOS() == llvm::Triple::IOS ||
322 !triple.isMacOSXVersionLT(10,5)));
325 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
326 ProgramStateRef state,
327 ObjCMessage msg) const {
328 ASTContext &Ctx = C.getASTContext();
330 // Check the return type of the message expression. A message to nil will
331 // return different values depending on the return type and the architecture.
332 QualType RetTy = msg.getType(Ctx);
333 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
334 const LocationContext *LCtx = C.getLocationContext();
336 if (CanRetTy->isStructureOrClassType()) {
337 // Structure returns are safe since the compiler zeroes them out.
338 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
339 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
343 // Other cases: check if sizeof(return type) > sizeof(void*)
344 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
345 .isConsumedExpr(msg.getMessageExpr())) {
346 // Compute: sizeof(void *) and sizeof(return type)
347 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
348 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
350 if (voidPtrSize < returnTypeSize &&
351 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
352 (Ctx.FloatTy == CanRetTy ||
353 Ctx.DoubleTy == CanRetTy ||
354 Ctx.LongDoubleTy == CanRetTy ||
355 Ctx.LongLongTy == CanRetTy ||
356 Ctx.UnsignedLongLongTy == CanRetTy))) {
357 if (ExplodedNode *N = C.generateSink(state))
358 emitNilReceiverBug(C, msg, N);
362 // Handle the safe cases where the return value is 0 if the
365 // FIXME: For now take the conservative approach that we only
366 // return null values if we *know* that the receiver is nil.
367 // This is because we can have surprises like:
369 // ... = [[NSScreens screens] objectAtIndex:0];
371 // What can happen is that [... screens] could return nil, but
372 // it most likely isn't nil. We should assume the semantics
373 // of this case unless we have *a lot* more knowledge.
375 SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
376 C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
380 C.addTransition(state);
383 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
384 mgr.registerChecker<CallAndMessageChecker>();