CallAndMessageChecker.cpp revision 76aadc346c3a4c363238a1e1232f324c3355d9e0
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), R));
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                                                                   R));
116      C.EmitReport(R);
117    }
118    return true;
119  }
120
121  if (!checkUninitFields)
122    return false;
123
124  if (const nonloc::LazyCompoundVal *LV =
125        dyn_cast<nonloc::LazyCompoundVal>(&V)) {
126
127    class FindUninitializedField {
128    public:
129      SmallVector<const FieldDecl *, 10> FieldChain;
130    private:
131      ASTContext &C;
132      StoreManager &StoreMgr;
133      MemRegionManager &MrMgr;
134      Store store;
135    public:
136      FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
137                             MemRegionManager &mrMgr, Store s)
138      : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
139
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);
149            T = (*I)->getType();
150            if (T->getAsStructureType()) {
151              if (Find(FR))
152                return true;
153            }
154            else {
155              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
156              if (V.isUndef())
157                return true;
158            }
159            FieldChain.pop_back();
160          }
161        }
162
163        return false;
164      }
165    };
166
167    const LazyCompoundValData *D = LV->getCVData();
168    FindUninitializedField F(C.getASTContext(),
169                             C.getState()->getStateManager().getStoreManager(),
170                             C.getSValBuilder().getRegionManager(),
171                             D->getStore());
172
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";
179
180        if (F.FieldChain.size() == 1)
181          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
182        else {
183          os << " (e.g., via the field chain: '";
184          bool first = true;
185          for (SmallVectorImpl<const FieldDecl *>::iterator
186               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
187            if (first)
188              first = false;
189            else
190              os << '.';
191            os << **DI;
192          }
193          os << "')";
194        }
195
196        // Generate a report for this bug.
197        BugReport *R = new BugReport(*BT, os.str(), N);
198        R->addRange(argRange);
199
200        // FIXME: enhance track back for uninitialized value for arbitrary
201        // memregions
202        C.EmitReport(R);
203      }
204      return true;
205    }
206  }
207
208  return false;
209}
210
211void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
212                                         CheckerContext &C) const{
213
214  const Expr *Callee = CE->getCallee()->IgnoreParens();
215  const LocationContext *LCtx = C.getLocationContext();
216  SVal L = C.getState()->getSVal(Callee, LCtx);
217
218  if (L.isUndef()) {
219    if (!BT_call_undef)
220      BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
221                                         "uninitalized pointer value"));
222    EmitBadCall(BT_call_undef.get(), C, CE);
223    return;
224  }
225
226  if (isa<loc::ConcreteInt>(L)) {
227    if (!BT_call_null)
228      BT_call_null.reset(
229        new BuiltinBug("Called function pointer is null (null dereference)"));
230    EmitBadCall(BT_call_null.get(), C, CE);
231  }
232
233  PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
234                      "Function call argument is an uninitialized value",
235                      BT_call_arg);
236}
237
238void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
239                                                CheckerContext &C) const {
240
241  ProgramStateRef state = C.getState();
242  const LocationContext *LCtx = C.getLocationContext();
243
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()) {
249        BugType *BT = 0;
250        if (msg.isPureMessageExpr()) {
251          if (!BT_msg_undef)
252            BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
253                                              "is an uninitialized value"));
254          BT = BT_msg_undef.get();
255        }
256        else {
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();
261        }
262        BugReport *R =
263          new BugReport(*BT, BT->getName(), N);
264        R->addRange(receiver->getSourceRange());
265        R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
266                                                                   receiver,
267                                                                   R));
268        C.EmitReport(R);
269      }
270      return;
271    } else {
272      // Bifurcate the state into nil and non-nil ones.
273      DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
274
275      ProgramStateRef notNilState, nilState;
276      llvm::tie(notNilState, nilState) = state->assume(receiverVal);
277
278      // Handle receiver must be nil.
279      if (nilState && !notNilState) {
280        HandleNilReceiver(C, state, msg);
281        return;
282      }
283    }
284  }
285
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);
292}
293
294void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
295                                               const ObjCMessage &msg,
296                                               ExplodedNode *N) const {
297
298  if (!BT_msg_ret)
299    BT_msg_ret.reset(
300      new BuiltinBug("Receiver in message expression is "
301                     "'nil' and returns a garbage value"));
302
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";
308
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,
313                                                                    receiver,
314                                                                    report));
315  }
316  C.EmitReport(report);
317}
318
319static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
320  return (triple.getVendor() == llvm::Triple::Apple &&
321          (triple.getOS() == llvm::Triple::IOS ||
322           !triple.isMacOSXVersionLT(10,5)));
323}
324
325void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
326                                              ProgramStateRef state,
327                                              ObjCMessage msg) const {
328  ASTContext &Ctx = C.getASTContext();
329
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();
335
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));
340    return;
341  }
342
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);
349
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);
359      return;
360    }
361
362    // Handle the safe cases where the return value is 0 if the
363    // receiver is nil.
364    //
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:
368    //
369    //   ... = [[NSScreens screens] objectAtIndex:0];
370    //
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.
374    //
375    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
376    C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
377    return;
378  }
379
380  C.addTransition(state);
381}
382
383void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
384  mgr.registerChecker<CallAndMessageChecker>();
385}
386