1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This defines CallAndMessageChecker, a builtin checker that checks for various
10 // errors of call and objc message expressions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/AST/ExprCXX.h"
15 #include "clang/AST/ParentMap.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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/ADT/StringExtras.h"
25 #include "llvm/Support/Casting.h"
26 #include "llvm/Support/raw_ostream.h"
27 
28 using namespace clang;
29 using namespace ento;
30 
31 namespace {
32 
33 class CallAndMessageChecker
34     : public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35                      check::PreCall> {
36   mutable std::unique_ptr<BugType> BT_call_null;
37   mutable std::unique_ptr<BugType> BT_call_undef;
38   mutable std::unique_ptr<BugType> BT_cxx_call_null;
39   mutable std::unique_ptr<BugType> BT_cxx_call_undef;
40   mutable std::unique_ptr<BugType> BT_call_arg;
41   mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
42   mutable std::unique_ptr<BugType> BT_msg_undef;
43   mutable std::unique_ptr<BugType> BT_objc_prop_undef;
44   mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
45   mutable std::unique_ptr<BugType> BT_msg_arg;
46   mutable std::unique_ptr<BugType> BT_msg_ret;
47   mutable std::unique_ptr<BugType> BT_call_few_args;
48 
49 public:
50   // These correspond with the checker options. Looking at other checkers such
51   // as MallocChecker and CStringChecker, this is similar as to how they pull
52   // off having a modeling class, but emitting diagnostics under a smaller
53   // checker's name that can be safely disabled without disturbing the
54   // underlaying modeling engine.
55   // The reason behind having *checker options* rather then actual *checkers*
56   // here is that CallAndMessage is among the oldest checkers out there, and can
57   // be responsible for the majority of the reports on any given project. This
58   // is obviously not ideal, but changing checker name has the consequence of
59   // changing the issue hashes associated with the reports, and databases
60   // relying on this (CodeChecker, for instance) would suffer greatly.
61   // If we ever end up making changes to the issue hash generation algorithm, or
62   // the warning messages here, we should totally jump on the opportunity to
63   // convert these to actual checkers.
64   enum CheckKind {
65     CK_FunctionPointer,
66     CK_ParameterCount,
67     CK_CXXThisMethodCall,
68     CK_CXXDeallocationArg,
69     CK_ArgInitializedness,
70     CK_ArgPointeeInitializedness,
71     CK_NilReceiver,
72     CK_UndefReceiver,
73     CK_NumCheckKinds
74   };
75 
76   bool ChecksEnabled[CK_NumCheckKinds] = {false};
77   // The original core.CallAndMessage checker name. This should rather be an
78   // array, as seen in MallocChecker and CStringChecker.
79   CheckerNameRef OriginalName;
80 
81   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
82 
83   /// Fill in the return value that results from messaging nil based on the
84   /// return type and architecture and diagnose if the return value will be
85   /// garbage.
86   void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;
87 
88   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
89 
90   ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,
91                                            CheckerContext &C,
92                                            ProgramStateRef State) const;
93 
94   ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,
95                                      CheckerContext &C,
96                                      ProgramStateRef State) const;
97 
98   ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,
99                                       ProgramStateRef State) const;
100 
101   ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,
102                                        CheckerContext &C,
103                                        ProgramStateRef State) const;
104 
105   ProgramStateRef checkArgInitializedness(const CallEvent &Call,
106                                           CheckerContext &C,
107                                           ProgramStateRef State) const;
108 
109 private:
110   bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
111                           const Expr *ArgEx, int ArgumentNumber,
112                           bool CheckUninitFields, const CallEvent &Call,
113                           std::unique_ptr<BugType> &BT,
114                           const ParmVarDecl *ParamDecl) const;
115 
116   static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
117   void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
118                           ExplodedNode *N) const;
119 
120   void HandleNilReceiver(CheckerContext &C,
121                          ProgramStateRef state,
122                          const ObjCMethodCall &msg) const;
123 
124   void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
125     if (!BT)
126       BT.reset(new BuiltinBug(OriginalName, desc));
127   }
128   bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
129                           SourceRange ArgRange, const Expr *ArgEx,
130                           std::unique_ptr<BugType> &BT,
131                           const ParmVarDecl *ParamDecl, const char *BD,
132                           int ArgumentNumber) const;
133 };
134 } // end anonymous namespace
135 
136 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
137                                         const Expr *BadE) {
138   ExplodedNode *N = C.generateErrorNode();
139   if (!N)
140     return;
141 
142   auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
143   if (BadE) {
144     R->addRange(BadE->getSourceRange());
145     if (BadE->isGLValue())
146       BadE = bugreporter::getDerefExpr(BadE);
147     bugreporter::trackExpressionValue(N, BadE, *R);
148   }
149   C.emitReport(std::move(R));
150 }
151 
152 static void describeUninitializedArgumentInCall(const CallEvent &Call,
153                                                 int ArgumentNumber,
154                                                 llvm::raw_svector_ostream &Os) {
155   switch (Call.getKind()) {
156   case CE_ObjCMessage: {
157     const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
158     switch (Msg.getMessageKind()) {
159     case OCM_Message:
160       Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
161          << " argument in message expression is an uninitialized value";
162       return;
163     case OCM_PropertyAccess:
164       assert(Msg.isSetter() && "Getters have no args");
165       Os << "Argument for property setter is an uninitialized value";
166       return;
167     case OCM_Subscript:
168       if (Msg.isSetter() && (ArgumentNumber == 0))
169         Os << "Argument for subscript setter is an uninitialized value";
170       else
171         Os << "Subscript index is an uninitialized value";
172       return;
173     }
174     llvm_unreachable("Unknown message kind.");
175   }
176   case CE_Block:
177     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
178        << " block call argument is an uninitialized value";
179     return;
180   default:
181     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
182        << " function call argument is an uninitialized value";
183     return;
184   }
185 }
186 
187 bool CallAndMessageChecker::uninitRefOrPointer(
188     CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
189     std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
190     int ArgumentNumber) const {
191 
192   // The pointee being uninitialized is a sign of code smell, not a bug, no need
193   // to sink here.
194   if (!ChecksEnabled[CK_ArgPointeeInitializedness])
195     return false;
196 
197   // No parameter declaration available, i.e. variadic function argument.
198   if(!ParamDecl)
199     return false;
200 
201   // If parameter is declared as pointer to const in function declaration,
202   // then check if corresponding argument in function call is
203   // pointing to undefined symbol value (uninitialized memory).
204   SmallString<200> Buf;
205   llvm::raw_svector_ostream Os(Buf);
206 
207   if (ParamDecl->getType()->isPointerType()) {
208     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
209        << " function call argument is a pointer to uninitialized value";
210   } else if (ParamDecl->getType()->isReferenceType()) {
211     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
212        << " function call argument is an uninitialized value";
213   } else
214     return false;
215 
216   if(!ParamDecl->getType()->getPointeeType().isConstQualified())
217     return false;
218 
219   if (const MemRegion *SValMemRegion = V.getAsRegion()) {
220     const ProgramStateRef State = C.getState();
221     const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
222     if (PSV.isUndef()) {
223       if (ExplodedNode *N = C.generateErrorNode()) {
224         LazyInit_BT(BD, BT);
225         auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
226         R->addRange(ArgRange);
227         if (ArgEx)
228           bugreporter::trackExpressionValue(N, ArgEx, *R);
229 
230         C.emitReport(std::move(R));
231       }
232       return true;
233     }
234   }
235   return false;
236 }
237 
238 namespace {
239 class FindUninitializedField {
240 public:
241   SmallVector<const FieldDecl *, 10> FieldChain;
242 
243 private:
244   StoreManager &StoreMgr;
245   MemRegionManager &MrMgr;
246   Store store;
247 
248 public:
249   FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
250                          Store s)
251       : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
252 
253   bool Find(const TypedValueRegion *R) {
254     QualType T = R->getValueType();
255     if (const RecordType *RT = T->getAsStructureType()) {
256       const RecordDecl *RD = RT->getDecl()->getDefinition();
257       assert(RD && "Referred record has no definition");
258       for (const auto *I : RD->fields()) {
259         const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
260         FieldChain.push_back(I);
261         T = I->getType();
262         if (T->getAsStructureType()) {
263           if (Find(FR))
264             return true;
265         } else {
266           const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
267           if (V.isUndef())
268             return true;
269         }
270         FieldChain.pop_back();
271       }
272     }
273 
274     return false;
275   }
276 };
277 } // namespace
278 
279 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
280                                                SVal V,
281                                                SourceRange ArgRange,
282                                                const Expr *ArgEx,
283                                                int ArgumentNumber,
284                                                bool CheckUninitFields,
285                                                const CallEvent &Call,
286                                                std::unique_ptr<BugType> &BT,
287                                                const ParmVarDecl *ParamDecl
288                                                ) const {
289   const char *BD = "Uninitialized argument value";
290 
291   if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
292                          ArgumentNumber))
293     return true;
294 
295   if (V.isUndef()) {
296     if (!ChecksEnabled[CK_ArgInitializedness]) {
297       C.addSink();
298       return true;
299     }
300     if (ExplodedNode *N = C.generateErrorNode()) {
301       LazyInit_BT(BD, BT);
302       // Generate a report for this bug.
303       SmallString<200> Buf;
304       llvm::raw_svector_ostream Os(Buf);
305       describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
306       auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
307 
308       R->addRange(ArgRange);
309       if (ArgEx)
310         bugreporter::trackExpressionValue(N, ArgEx, *R);
311       C.emitReport(std::move(R));
312     }
313     return true;
314   }
315 
316   if (!CheckUninitFields)
317     return false;
318 
319   if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
320     const LazyCompoundValData *D = LV->getCVData();
321     FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
322                              C.getSValBuilder().getRegionManager(),
323                              D->getStore());
324 
325     if (F.Find(D->getRegion())) {
326       if (!ChecksEnabled[CK_ArgInitializedness]) {
327         C.addSink();
328         return true;
329       }
330       if (ExplodedNode *N = C.generateErrorNode()) {
331         LazyInit_BT(BD, BT);
332         SmallString<512> Str;
333         llvm::raw_svector_ostream os(Str);
334         os << "Passed-by-value struct argument contains uninitialized data";
335 
336         if (F.FieldChain.size() == 1)
337           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
338         else {
339           os << " (e.g., via the field chain: '";
340           bool first = true;
341           for (SmallVectorImpl<const FieldDecl *>::iterator
342                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
343             if (first)
344               first = false;
345             else
346               os << '.';
347             os << **DI;
348           }
349           os << "')";
350         }
351 
352         // Generate a report for this bug.
353         auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
354         R->addRange(ArgRange);
355 
356         if (ArgEx)
357           bugreporter::trackExpressionValue(N, ArgEx, *R);
358         // FIXME: enhance track back for uninitialized value for arbitrary
359         // memregions
360         C.emitReport(std::move(R));
361       }
362       return true;
363     }
364   }
365 
366   return false;
367 }
368 
369 ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
370     const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
371 
372   const Expr *Callee = CE->getCallee()->IgnoreParens();
373   const LocationContext *LCtx = C.getLocationContext();
374   SVal L = State->getSVal(Callee, LCtx);
375 
376   if (L.isUndef()) {
377     if (!ChecksEnabled[CK_FunctionPointer]) {
378       C.addSink(State);
379       return nullptr;
380     }
381     if (!BT_call_undef)
382       BT_call_undef.reset(new BuiltinBug(
383           OriginalName,
384           "Called function pointer is an uninitialized pointer value"));
385     emitBadCall(BT_call_undef.get(), C, Callee);
386     return nullptr;
387   }
388 
389   ProgramStateRef StNonNull, StNull;
390   std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
391 
392   if (StNull && !StNonNull) {
393     if (!ChecksEnabled[CK_FunctionPointer]) {
394       C.addSink(StNull);
395       return nullptr;
396     }
397     if (!BT_call_null)
398       BT_call_null.reset(new BuiltinBug(
399           OriginalName, "Called function pointer is null (null dereference)"));
400     emitBadCall(BT_call_null.get(), C, Callee);
401     return nullptr;
402   }
403 
404   return StNonNull;
405 }
406 
407 ProgramStateRef CallAndMessageChecker::checkParameterCount(
408     const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
409 
410   // If we have a function or block declaration, we can make sure we pass
411   // enough parameters.
412   unsigned Params = Call.parameters().size();
413   if (Call.getNumArgs() >= Params)
414     return State;
415 
416   if (!ChecksEnabled[CK_ParameterCount]) {
417     C.addSink(State);
418     return nullptr;
419   }
420 
421   ExplodedNode *N = C.generateErrorNode();
422   if (!N)
423     return nullptr;
424 
425   LazyInit_BT("Function call with too few arguments", BT_call_few_args);
426 
427   SmallString<512> Str;
428   llvm::raw_svector_ostream os(Str);
429   if (isa<AnyFunctionCall>(Call)) {
430     os << "Function ";
431   } else {
432     assert(isa<BlockCall>(Call));
433     os << "Block ";
434   }
435   os << "taking " << Params << " argument" << (Params == 1 ? "" : "s")
436      << " is called with fewer (" << Call.getNumArgs() << ")";
437 
438   C.emitReport(
439       std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
440   return nullptr;
441 }
442 
443 ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
444     const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {
445 
446   SVal V = CC->getCXXThisVal();
447   if (V.isUndef()) {
448     if (!ChecksEnabled[CK_CXXThisMethodCall]) {
449       C.addSink(State);
450       return nullptr;
451     }
452     if (!BT_cxx_call_undef)
453       BT_cxx_call_undef.reset(new BuiltinBug(
454           OriginalName, "Called C++ object pointer is uninitialized"));
455     emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
456     return nullptr;
457   }
458 
459   ProgramStateRef StNonNull, StNull;
460   std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
461 
462   if (StNull && !StNonNull) {
463     if (!ChecksEnabled[CK_CXXThisMethodCall]) {
464       C.addSink(StNull);
465       return nullptr;
466     }
467     if (!BT_cxx_call_null)
468       BT_cxx_call_null.reset(
469           new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
470     emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
471     return nullptr;
472   }
473 
474   return StNonNull;
475 }
476 
477 ProgramStateRef
478 CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
479                                             CheckerContext &C,
480                                             ProgramStateRef State) const {
481   const CXXDeleteExpr *DE = DC->getOriginExpr();
482   assert(DE);
483   SVal Arg = C.getSVal(DE->getArgument());
484   if (!Arg.isUndef())
485     return State;
486 
487   if (!ChecksEnabled[CK_CXXDeallocationArg]) {
488     C.addSink(State);
489     return nullptr;
490   }
491 
492   StringRef Desc;
493   ExplodedNode *N = C.generateErrorNode();
494   if (!N)
495     return nullptr;
496   if (!BT_cxx_delete_undef)
497     BT_cxx_delete_undef.reset(
498         new BuiltinBug(OriginalName, "Uninitialized argument value"));
499   if (DE->isArrayFormAsWritten())
500     Desc = "Argument to 'delete[]' is uninitialized";
501   else
502     Desc = "Argument to 'delete' is uninitialized";
503   BugType *BT = BT_cxx_delete_undef.get();
504   auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
505   bugreporter::trackExpressionValue(N, DE, *R);
506   C.emitReport(std::move(R));
507   return nullptr;
508 }
509 
510 ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
511     const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
512 
513   const Decl *D = Call.getDecl();
514 
515   // Don't check for uninitialized field values in arguments if the
516   // caller has a body that is available and we have the chance to inline it.
517   // This is a hack, but is a reasonable compromise betweens sometimes warning
518   // and sometimes not depending on if we decide to inline a function.
519   const bool checkUninitFields =
520       !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
521 
522   std::unique_ptr<BugType> *BT;
523   if (isa<ObjCMethodCall>(Call))
524     BT = &BT_msg_arg;
525   else
526     BT = &BT_call_arg;
527 
528   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
529   for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
530     const ParmVarDecl *ParamDecl = nullptr;
531     if (FD && i < FD->getNumParams())
532       ParamDecl = FD->getParamDecl(i);
533     if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
534                            Call.getArgExpr(i), i, checkUninitFields, Call, *BT,
535                            ParamDecl))
536       return nullptr;
537   }
538   return State;
539 }
540 
541 void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
542                                          CheckerContext &C) const {
543   ProgramStateRef State = C.getState();
544 
545   if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))
546     State = checkFunctionPointerCall(CE, C, State);
547 
548   if (!State)
549     return;
550 
551   if (Call.getDecl())
552     State = checkParameterCount(Call, C, State);
553 
554   if (!State)
555     return;
556 
557   if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))
558     State = checkCXXMethodCall(CC, C, State);
559 
560   if (!State)
561     return;
562 
563   if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))
564     State = checkCXXDeallocation(DC, C, State);
565 
566   if (!State)
567     return;
568 
569   State = checkArgInitializedness(Call, C, State);
570 
571   // If we make it here, record our assumptions about the callee.
572   C.addTransition(State);
573 }
574 
575 void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
576                                                 CheckerContext &C) const {
577   SVal recVal = msg.getReceiverSVal();
578   if (recVal.isUndef()) {
579     if (!ChecksEnabled[CK_UndefReceiver]) {
580       C.addSink();
581       return;
582     }
583     if (ExplodedNode *N = C.generateErrorNode()) {
584       BugType *BT = nullptr;
585       switch (msg.getMessageKind()) {
586       case OCM_Message:
587         if (!BT_msg_undef)
588           BT_msg_undef.reset(new BuiltinBug(OriginalName,
589                                             "Receiver in message expression "
590                                             "is an uninitialized value"));
591         BT = BT_msg_undef.get();
592         break;
593       case OCM_PropertyAccess:
594         if (!BT_objc_prop_undef)
595           BT_objc_prop_undef.reset(new BuiltinBug(
596               OriginalName,
597               "Property access on an uninitialized object pointer"));
598         BT = BT_objc_prop_undef.get();
599         break;
600       case OCM_Subscript:
601         if (!BT_objc_subscript_undef)
602           BT_objc_subscript_undef.reset(new BuiltinBug(
603               OriginalName,
604               "Subscript access on an uninitialized object pointer"));
605         BT = BT_objc_subscript_undef.get();
606         break;
607       }
608       assert(BT && "Unknown message kind.");
609 
610       auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
611       const ObjCMessageExpr *ME = msg.getOriginExpr();
612       R->addRange(ME->getReceiverRange());
613 
614       // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
615       if (const Expr *ReceiverE = ME->getInstanceReceiver())
616         bugreporter::trackExpressionValue(N, ReceiverE, *R);
617       C.emitReport(std::move(R));
618     }
619     return;
620   }
621 }
622 
623 void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
624                                                 CheckerContext &C) const {
625   HandleNilReceiver(C, C.getState(), msg);
626 }
627 
628 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
629                                                const ObjCMethodCall &msg,
630                                                ExplodedNode *N) const {
631   if (!ChecksEnabled[CK_NilReceiver]) {
632     C.addSink();
633     return;
634   }
635 
636   if (!BT_msg_ret)
637     BT_msg_ret.reset(new BuiltinBug(OriginalName,
638                                     "Receiver in message expression is 'nil'"));
639 
640   const ObjCMessageExpr *ME = msg.getOriginExpr();
641 
642   QualType ResTy = msg.getResultType();
643 
644   SmallString<200> buf;
645   llvm::raw_svector_ostream os(buf);
646   os << "The receiver of message '";
647   ME->getSelector().print(os);
648   os << "' is nil";
649   if (ResTy->isReferenceType()) {
650     os << ", which results in forming a null reference";
651   } else {
652     os << " and returns a value of type '";
653     msg.getResultType().print(os, C.getLangOpts());
654     os << "' that will be garbage";
655   }
656 
657   auto report =
658       std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
659   report->addRange(ME->getReceiverRange());
660   // FIXME: This won't track "self" in messages to super.
661   if (const Expr *receiver = ME->getInstanceReceiver()) {
662     bugreporter::trackExpressionValue(N, receiver, *report);
663   }
664   C.emitReport(std::move(report));
665 }
666 
667 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
668   return (triple.getVendor() == llvm::Triple::Apple &&
669           (triple.isiOS() || triple.isWatchOS() ||
670            !triple.isMacOSXVersionLT(10,5)));
671 }
672 
673 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
674                                               ProgramStateRef state,
675                                               const ObjCMethodCall &Msg) const {
676   ASTContext &Ctx = C.getASTContext();
677   static CheckerProgramPointTag Tag(this, "NilReceiver");
678 
679   // Check the return type of the message expression.  A message to nil will
680   // return different values depending on the return type and the architecture.
681   QualType RetTy = Msg.getResultType();
682   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
683   const LocationContext *LCtx = C.getLocationContext();
684 
685   if (CanRetTy->isStructureOrClassType()) {
686     // Structure returns are safe since the compiler zeroes them out.
687     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
688     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
689     return;
690   }
691 
692   // Other cases: check if sizeof(return type) > sizeof(void*)
693   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
694                                   .isConsumedExpr(Msg.getOriginExpr())) {
695     // Compute: sizeof(void *) and sizeof(return type)
696     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
697     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
698 
699     if (CanRetTy.getTypePtr()->isReferenceType()||
700         (voidPtrSize < returnTypeSize &&
701          !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
702            (Ctx.FloatTy == CanRetTy ||
703             Ctx.DoubleTy == CanRetTy ||
704             Ctx.LongDoubleTy == CanRetTy ||
705             Ctx.LongLongTy == CanRetTy ||
706             Ctx.UnsignedLongLongTy == CanRetTy)))) {
707       if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
708         emitNilReceiverBug(C, Msg, N);
709       return;
710     }
711 
712     // Handle the safe cases where the return value is 0 if the
713     // receiver is nil.
714     //
715     // FIXME: For now take the conservative approach that we only
716     // return null values if we *know* that the receiver is nil.
717     // This is because we can have surprises like:
718     //
719     //   ... = [[NSScreens screens] objectAtIndex:0];
720     //
721     // What can happen is that [... screens] could return nil, but
722     // it most likely isn't nil.  We should assume the semantics
723     // of this case unless we have *a lot* more knowledge.
724     //
725     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
726     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
727     return;
728   }
729 
730   C.addTransition(state);
731 }
732 
733 void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
734   mgr.registerChecker<CallAndMessageChecker>();
735 }
736 
737 bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
738   return true;
739 }
740 
741 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
742   CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
743 
744   checker->OriginalName = mgr.getCurrentCheckerName();
745 
746 #define QUERY_CHECKER_OPTION(OPTION)                                           \
747   checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] =                 \
748       mgr.getAnalyzerOptions().getCheckerBooleanOption(                        \
749           mgr.getCurrentCheckerName(), #OPTION);
750 
751   QUERY_CHECKER_OPTION(FunctionPointer)
752   QUERY_CHECKER_OPTION(ParameterCount)
753   QUERY_CHECKER_OPTION(CXXThisMethodCall)
754   QUERY_CHECKER_OPTION(CXXDeallocationArg)
755   QUERY_CHECKER_OPTION(ArgInitializedness)
756   QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
757   QUERY_CHECKER_OPTION(NilReceiver)
758   QUERY_CHECKER_OPTION(UndefReceiver)
759 }
760 
761 bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
762   return true;
763 }
764