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