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