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