1d99bd55aSTed Kremenek //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This defines CallAndMessageChecker, a builtin checker that checks for various
10d99bd55aSTed Kremenek // errors of call and objc message expressions.
11d99bd55aSTed Kremenek //
12d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
13d99bd55aSTed Kremenek 
143d0d2fefSKirstóf Umann #include "clang/AST/ExprCXX.h"
153a02247dSChandler Carruth #include "clang/AST/ParentMap.h"
163a02247dSChandler Carruth #include "clang/Basic/TargetInfo.h"
173d0d2fefSKirstóf Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
183a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
196a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
206d6801c5SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
214f7df9beSJordan Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
226d6801c5SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
234903802fSBenjamin Kramer #include "llvm/ADT/SmallString.h"
243d8d6ed0SDaniel Marjamaki #include "llvm/ADT/StringExtras.h"
253d0d2fefSKirstóf Umann #include "llvm/Support/Casting.h"
26444a1304SBenjamin Kramer #include "llvm/Support/raw_ostream.h"
27d99bd55aSTed Kremenek 
28d99bd55aSTed Kremenek using namespace clang;
29d99bd55aSTed Kremenek using namespace ento;
30d99bd55aSTed Kremenek 
31d99bd55aSTed Kremenek namespace {
32821a3a0fSJordan Rose 
33d99bd55aSTed Kremenek class CallAndMessageChecker
343d0d2fefSKirstóf Umann     : public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35682b3162SJordan Rose                      check::PreCall> {
36b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_call_null;
37b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_call_undef;
38b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_cxx_call_null;
39b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_cxx_call_undef;
40b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_call_arg;
41b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
42b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_msg_undef;
43b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_objc_prop_undef;
44b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
45b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_msg_arg;
46b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_msg_ret;
47b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT_call_few_args;
48b8984329SAhmed Charles 
49d99bd55aSTed Kremenek public:
501c8f999eSKirstóf Umann   // These correspond with the checker options. Looking at other checkers such
511c8f999eSKirstóf Umann   // as MallocChecker and CStringChecker, this is similar as to how they pull
521c8f999eSKirstóf Umann   // off having a modeling class, but emitting diagnostics under a smaller
531c8f999eSKirstóf Umann   // checker's name that can be safely disabled without disturbing the
541c8f999eSKirstóf Umann   // underlaying modeling engine.
551c8f999eSKirstóf Umann   // The reason behind having *checker options* rather then actual *checkers*
561c8f999eSKirstóf Umann   // here is that CallAndMessage is among the oldest checkers out there, and can
571c8f999eSKirstóf Umann   // be responsible for the majority of the reports on any given project. This
581c8f999eSKirstóf Umann   // is obviously not ideal, but changing checker name has the consequence of
591c8f999eSKirstóf Umann   // changing the issue hashes associated with the reports, and databases
601c8f999eSKirstóf Umann   // relying on this (CodeChecker, for instance) would suffer greatly.
611c8f999eSKirstóf Umann   // If we ever end up making changes to the issue hash generation algorithm, or
621c8f999eSKirstóf Umann   // the warning messages here, we should totally jump on the opportunity to
631c8f999eSKirstóf Umann   // convert these to actual checkers.
641c8f999eSKirstóf Umann   enum CheckKind {
651c8f999eSKirstóf Umann     CK_FunctionPointer,
661c8f999eSKirstóf Umann     CK_ParameterCount,
671c8f999eSKirstóf Umann     CK_CXXThisMethodCall,
681c8f999eSKirstóf Umann     CK_CXXDeallocationArg,
691c8f999eSKirstóf Umann     CK_ArgInitializedness,
701c8f999eSKirstóf Umann     CK_ArgPointeeInitializedness,
711c8f999eSKirstóf Umann     CK_NilReceiver,
721c8f999eSKirstóf Umann     CK_UndefReceiver,
731c8f999eSKirstóf Umann     CK_NumCheckKinds
741c8f999eSKirstóf Umann   };
75d99bd55aSTed Kremenek 
76*5114db93SVince Bridgers   bool ChecksEnabled[CK_NumCheckKinds] = {false};
771c8f999eSKirstóf Umann   // The original core.CallAndMessage checker name. This should rather be an
781c8f999eSKirstóf Umann   // array, as seen in MallocChecker and CStringChecker.
791c8f999eSKirstóf Umann   CheckerNameRef OriginalName;
803d0d2fefSKirstóf Umann 
81547060b3SJordan Rose   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
82ca5ab2b0SDevin Coughlin 
83ca5ab2b0SDevin Coughlin   /// Fill in the return value that results from messaging nil based on the
84ca5ab2b0SDevin Coughlin   /// return type and architecture and diagnose if the return value will be
85ca5ab2b0SDevin Coughlin   /// garbage.
86ca5ab2b0SDevin Coughlin   void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;
87ca5ab2b0SDevin Coughlin 
88682b3162SJordan Rose   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
89d99bd55aSTed Kremenek 
90eeff1a97SKirstóf Umann   ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,
91eeff1a97SKirstóf Umann                                            CheckerContext &C,
92eeff1a97SKirstóf Umann                                            ProgramStateRef State) const;
93eeff1a97SKirstóf Umann 
94eeff1a97SKirstóf Umann   ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,
95eeff1a97SKirstóf Umann                                      CheckerContext &C,
96eeff1a97SKirstóf Umann                                      ProgramStateRef State) const;
97eeff1a97SKirstóf Umann 
98eeff1a97SKirstóf Umann   ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,
99eeff1a97SKirstóf Umann                                       ProgramStateRef State) const;
100eeff1a97SKirstóf Umann 
101eeff1a97SKirstóf Umann   ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,
102eeff1a97SKirstóf Umann                                        CheckerContext &C,
103eeff1a97SKirstóf Umann                                        ProgramStateRef State) const;
104eeff1a97SKirstóf Umann 
105eeff1a97SKirstóf Umann   ProgramStateRef checkArgInitializedness(const CallEvent &Call,
106eeff1a97SKirstóf Umann                                           CheckerContext &C,
107eeff1a97SKirstóf Umann                                           ProgramStateRef State) const;
108eeff1a97SKirstóf Umann 
109d99bd55aSTed Kremenek private:
110821a3a0fSJordan Rose   bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
1113d8d6ed0SDaniel Marjamaki                           const Expr *ArgEx, int ArgumentNumber,
112821a3a0fSJordan Rose                           bool CheckUninitFields, const CallEvent &Call,
113821a3a0fSJordan Rose                           std::unique_ptr<BugType> &BT,
114821a3a0fSJordan Rose                           const ParmVarDecl *ParamDecl) const;
115d99bd55aSTed Kremenek 
11692e1449bSJordan Rose   static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
117547060b3SJordan Rose   void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
1186d6801c5SArgyrios Kyrtzidis                           ExplodedNode *N) const;
119d99bd55aSTed Kremenek 
120001fd5b4STed Kremenek   void HandleNilReceiver(CheckerContext &C,
12149b1e38eSTed Kremenek                          ProgramStateRef state,
122547060b3SJordan Rose                          const ObjCMethodCall &msg) const;
123d99bd55aSTed Kremenek 
LazyInit_BT(const char * desc,std::unique_ptr<BugType> & BT) const124b8984329SAhmed Charles   void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
125d99bd55aSTed Kremenek     if (!BT)
1261c8f999eSKirstóf Umann       BT.reset(new BuiltinBug(OriginalName, desc));
127d99bd55aSTed Kremenek   }
128821a3a0fSJordan Rose   bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
1293d8d6ed0SDaniel Marjamaki                           SourceRange ArgRange, const Expr *ArgEx,
1303d8d6ed0SDaniel Marjamaki                           std::unique_ptr<BugType> &BT,
1313d8d6ed0SDaniel Marjamaki                           const ParmVarDecl *ParamDecl, const char *BD,
1323d8d6ed0SDaniel Marjamaki                           int ArgumentNumber) const;
133d99bd55aSTed Kremenek };
134d99bd55aSTed Kremenek } // end anonymous namespace
135d99bd55aSTed Kremenek 
emitBadCall(BugType * BT,CheckerContext & C,const Expr * BadE)13692e1449bSJordan Rose void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
13792e1449bSJordan Rose                                         const Expr *BadE) {
138e39bd407SDevin Coughlin   ExplodedNode *N = C.generateErrorNode();
139d99bd55aSTed Kremenek   if (!N)
140d99bd55aSTed Kremenek     return;
141d99bd55aSTed Kremenek 
14272649423SKristof Umann   auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
14392e1449bSJordan Rose   if (BadE) {
14492e1449bSJordan Rose     R->addRange(BadE->getSourceRange());
145aea020f0SJordan Rose     if (BadE->isGLValue())
146aea020f0SJordan Rose       BadE = bugreporter::getDerefExpr(BadE);
147b2cf0063SGeorge Karpenkov     bugreporter::trackExpressionValue(N, BadE, *R);
14892e1449bSJordan Rose   }
1498d3a7a56SAaron Ballman   C.emitReport(std::move(R));
150d99bd55aSTed Kremenek }
151d99bd55aSTed Kremenek 
describeUninitializedArgumentInCall(const CallEvent & Call,int ArgumentNumber,llvm::raw_svector_ostream & Os)1523d8d6ed0SDaniel Marjamaki static void describeUninitializedArgumentInCall(const CallEvent &Call,
1533d8d6ed0SDaniel Marjamaki                                                 int ArgumentNumber,
1543d8d6ed0SDaniel Marjamaki                                                 llvm::raw_svector_ostream &Os) {
155627b046cSJordan Rose   switch (Call.getKind()) {
156627b046cSJordan Rose   case CE_ObjCMessage: {
157627b046cSJordan Rose     const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
158627b046cSJordan Rose     switch (Msg.getMessageKind()) {
159627b046cSJordan Rose     case OCM_Message:
1603d8d6ed0SDaniel Marjamaki       Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
1613d8d6ed0SDaniel Marjamaki          << " argument in message expression is an uninitialized value";
1623d8d6ed0SDaniel Marjamaki       return;
163627b046cSJordan Rose     case OCM_PropertyAccess:
164627b046cSJordan Rose       assert(Msg.isSetter() && "Getters have no args");
1653d8d6ed0SDaniel Marjamaki       Os << "Argument for property setter is an uninitialized value";
1663d8d6ed0SDaniel Marjamaki       return;
167627b046cSJordan Rose     case OCM_Subscript:
1683d8d6ed0SDaniel Marjamaki       if (Msg.isSetter() && (ArgumentNumber == 0))
1693d8d6ed0SDaniel Marjamaki         Os << "Argument for subscript setter is an uninitialized value";
1703d8d6ed0SDaniel Marjamaki       else
1713d8d6ed0SDaniel Marjamaki         Os << "Subscript index is an uninitialized value";
1723d8d6ed0SDaniel Marjamaki       return;
173627b046cSJordan Rose     }
174627b046cSJordan Rose     llvm_unreachable("Unknown message kind.");
175627b046cSJordan Rose   }
176627b046cSJordan Rose   case CE_Block:
1773d8d6ed0SDaniel Marjamaki     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
1783d8d6ed0SDaniel Marjamaki        << " block call argument is an uninitialized value";
1793d8d6ed0SDaniel Marjamaki     return;
180627b046cSJordan Rose   default:
1813d8d6ed0SDaniel Marjamaki     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
1823d8d6ed0SDaniel Marjamaki        << " function call argument is an uninitialized value";
1833d8d6ed0SDaniel Marjamaki     return;
184627b046cSJordan Rose   }
185627b046cSJordan Rose }
186627b046cSJordan Rose 
uninitRefOrPointer(CheckerContext & C,const SVal & V,SourceRange ArgRange,const Expr * ArgEx,std::unique_ptr<BugType> & BT,const ParmVarDecl * ParamDecl,const char * BD,int ArgumentNumber) const1873d8d6ed0SDaniel Marjamaki bool CallAndMessageChecker::uninitRefOrPointer(
1883d8d6ed0SDaniel Marjamaki     CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
1893d8d6ed0SDaniel Marjamaki     std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
1903d8d6ed0SDaniel Marjamaki     int ArgumentNumber) const {
1911c8f999eSKirstóf Umann 
1921c8f999eSKirstóf Umann   // The pointee being uninitialized is a sign of code smell, not a bug, no need
1931c8f999eSKirstóf Umann   // to sink here.
1941c8f999eSKirstóf Umann   if (!ChecksEnabled[CK_ArgPointeeInitializedness])
195821a3a0fSJordan Rose     return false;
196821a3a0fSJordan Rose 
197821a3a0fSJordan Rose   // No parameter declaration available, i.e. variadic function argument.
198821a3a0fSJordan Rose   if(!ParamDecl)
199821a3a0fSJordan Rose     return false;
200821a3a0fSJordan Rose 
201821a3a0fSJordan Rose   // If parameter is declared as pointer to const in function declaration,
202821a3a0fSJordan Rose   // then check if corresponding argument in function call is
203821a3a0fSJordan Rose   // pointing to undefined symbol value (uninitialized memory).
2043d8d6ed0SDaniel Marjamaki   SmallString<200> Buf;
2053d8d6ed0SDaniel Marjamaki   llvm::raw_svector_ostream Os(Buf);
206821a3a0fSJordan Rose 
207821a3a0fSJordan Rose   if (ParamDecl->getType()->isPointerType()) {
2083d8d6ed0SDaniel Marjamaki     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
2093d8d6ed0SDaniel Marjamaki        << " function call argument is a pointer to uninitialized value";
210821a3a0fSJordan Rose   } else if (ParamDecl->getType()->isReferenceType()) {
2113d8d6ed0SDaniel Marjamaki     Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
2123d8d6ed0SDaniel Marjamaki        << " function call argument is an uninitialized value";
213821a3a0fSJordan Rose   } else
214821a3a0fSJordan Rose     return false;
215821a3a0fSJordan Rose 
216821a3a0fSJordan Rose   if(!ParamDecl->getType()->getPointeeType().isConstQualified())
217821a3a0fSJordan Rose     return false;
218821a3a0fSJordan Rose 
219821a3a0fSJordan Rose   if (const MemRegion *SValMemRegion = V.getAsRegion()) {
220821a3a0fSJordan Rose     const ProgramStateRef State = C.getState();
2213ef5deb3SArtem Dergachev     const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
222821a3a0fSJordan Rose     if (PSV.isUndef()) {
223e39bd407SDevin Coughlin       if (ExplodedNode *N = C.generateErrorNode()) {
224821a3a0fSJordan Rose         LazyInit_BT(BD, BT);
2252f169e7cSArtem Dergachev         auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
226821a3a0fSJordan Rose         R->addRange(ArgRange);
227b2cf0063SGeorge Karpenkov         if (ArgEx)
228b2cf0063SGeorge Karpenkov           bugreporter::trackExpressionValue(N, ArgEx, *R);
229b2cf0063SGeorge Karpenkov 
2308d3a7a56SAaron Ballman         C.emitReport(std::move(R));
231821a3a0fSJordan Rose       }
232821a3a0fSJordan Rose       return true;
233821a3a0fSJordan Rose     }
234821a3a0fSJordan Rose   }
235821a3a0fSJordan Rose   return false;
236821a3a0fSJordan Rose }
237821a3a0fSJordan Rose 
238c55e9975SBenjamin Kramer namespace {
239eae57a2bSGeorge Karpenkov class FindUninitializedField {
240eae57a2bSGeorge Karpenkov public:
241eae57a2bSGeorge Karpenkov   SmallVector<const FieldDecl *, 10> FieldChain;
242eae57a2bSGeorge Karpenkov 
243eae57a2bSGeorge Karpenkov private:
244eae57a2bSGeorge Karpenkov   StoreManager &StoreMgr;
245eae57a2bSGeorge Karpenkov   MemRegionManager &MrMgr;
246eae57a2bSGeorge Karpenkov   Store store;
247eae57a2bSGeorge Karpenkov 
248eae57a2bSGeorge Karpenkov public:
FindUninitializedField(StoreManager & storeMgr,MemRegionManager & mrMgr,Store s)249eae57a2bSGeorge Karpenkov   FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
250eae57a2bSGeorge Karpenkov                          Store s)
251eae57a2bSGeorge Karpenkov       : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
252eae57a2bSGeorge Karpenkov 
Find(const TypedValueRegion * R)253eae57a2bSGeorge Karpenkov   bool Find(const TypedValueRegion *R) {
254eae57a2bSGeorge Karpenkov     QualType T = R->getValueType();
255eae57a2bSGeorge Karpenkov     if (const RecordType *RT = T->getAsStructureType()) {
256eae57a2bSGeorge Karpenkov       const RecordDecl *RD = RT->getDecl()->getDefinition();
257eae57a2bSGeorge Karpenkov       assert(RD && "Referred record has no definition");
258eae57a2bSGeorge Karpenkov       for (const auto *I : RD->fields()) {
259eae57a2bSGeorge Karpenkov         const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
260eae57a2bSGeorge Karpenkov         FieldChain.push_back(I);
261eae57a2bSGeorge Karpenkov         T = I->getType();
262eae57a2bSGeorge Karpenkov         if (T->getAsStructureType()) {
263eae57a2bSGeorge Karpenkov           if (Find(FR))
264eae57a2bSGeorge Karpenkov             return true;
265eae57a2bSGeorge Karpenkov         } else {
266eae57a2bSGeorge Karpenkov           const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
267eae57a2bSGeorge Karpenkov           if (V.isUndef())
268eae57a2bSGeorge Karpenkov             return true;
269eae57a2bSGeorge Karpenkov         }
270eae57a2bSGeorge Karpenkov         FieldChain.pop_back();
271eae57a2bSGeorge Karpenkov       }
272eae57a2bSGeorge Karpenkov     }
273eae57a2bSGeorge Karpenkov 
274eae57a2bSGeorge Karpenkov     return false;
275eae57a2bSGeorge Karpenkov   }
276eae57a2bSGeorge Karpenkov };
277c55e9975SBenjamin Kramer } // namespace
278eae57a2bSGeorge Karpenkov 
PreVisitProcessArg(CheckerContext & C,SVal V,SourceRange ArgRange,const Expr * ArgEx,int ArgumentNumber,bool CheckUninitFields,const CallEvent & Call,std::unique_ptr<BugType> & BT,const ParmVarDecl * ParamDecl) const279821a3a0fSJordan Rose bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
280821a3a0fSJordan Rose                                                SVal V,
281821a3a0fSJordan Rose                                                SourceRange ArgRange,
282821a3a0fSJordan Rose                                                const Expr *ArgEx,
2833d8d6ed0SDaniel Marjamaki                                                int ArgumentNumber,
284821a3a0fSJordan Rose                                                bool CheckUninitFields,
285821a3a0fSJordan Rose                                                const CallEvent &Call,
286821a3a0fSJordan Rose                                                std::unique_ptr<BugType> &BT,
287821a3a0fSJordan Rose                                                const ParmVarDecl *ParamDecl
288821a3a0fSJordan Rose                                                ) const {
289821a3a0fSJordan Rose   const char *BD = "Uninitialized argument value";
290821a3a0fSJordan Rose 
2913d8d6ed0SDaniel Marjamaki   if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
2923d8d6ed0SDaniel Marjamaki                          ArgumentNumber))
293821a3a0fSJordan Rose     return true;
294821a3a0fSJordan Rose 
295d99bd55aSTed Kremenek   if (V.isUndef()) {
2961c8f999eSKirstóf Umann     if (!ChecksEnabled[CK_ArgInitializedness]) {
2971c8f999eSKirstóf Umann       C.addSink();
2981c8f999eSKirstóf Umann       return true;
2991c8f999eSKirstóf Umann     }
300e39bd407SDevin Coughlin     if (ExplodedNode *N = C.generateErrorNode()) {
301821a3a0fSJordan Rose       LazyInit_BT(BD, BT);
302d99bd55aSTed Kremenek       // Generate a report for this bug.
3033d8d6ed0SDaniel Marjamaki       SmallString<200> Buf;
3043d8d6ed0SDaniel Marjamaki       llvm::raw_svector_ostream Os(Buf);
3053d8d6ed0SDaniel Marjamaki       describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
3062f169e7cSArtem Dergachev       auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
3073d8d6ed0SDaniel Marjamaki 
308821a3a0fSJordan Rose       R->addRange(ArgRange);
309821a3a0fSJordan Rose       if (ArgEx)
310b2cf0063SGeorge Karpenkov         bugreporter::trackExpressionValue(N, ArgEx, *R);
3118d3a7a56SAaron Ballman       C.emitReport(std::move(R));
312d99bd55aSTed Kremenek     }
313d99bd55aSTed Kremenek     return true;
314d99bd55aSTed Kremenek   }
315d99bd55aSTed Kremenek 
316821a3a0fSJordan Rose   if (!CheckUninitFields)
3176762a940STed Kremenek     return false;
3186762a940STed Kremenek 
319eae57a2bSGeorge Karpenkov   if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
320d99bd55aSTed Kremenek     const LazyCompoundValData *D = LV->getCVData();
321d1d76b2dSBenjamin Kramer     FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
322d99bd55aSTed Kremenek                              C.getSValBuilder().getRegionManager(),
323d99bd55aSTed Kremenek                              D->getStore());
324d99bd55aSTed Kremenek 
325d99bd55aSTed Kremenek     if (F.Find(D->getRegion())) {
3261c8f999eSKirstóf Umann       if (!ChecksEnabled[CK_ArgInitializedness]) {
3271c8f999eSKirstóf Umann         C.addSink();
3281c8f999eSKirstóf Umann         return true;
3291c8f999eSKirstóf Umann       }
330e39bd407SDevin Coughlin       if (ExplodedNode *N = C.generateErrorNode()) {
331821a3a0fSJordan Rose         LazyInit_BT(BD, BT);
3322c1dd271SDylan Noblesmith         SmallString<512> Str;
333d99bd55aSTed Kremenek         llvm::raw_svector_ostream os(Str);
334d99bd55aSTed Kremenek         os << "Passed-by-value struct argument contains uninitialized data";
335d99bd55aSTed Kremenek 
336d99bd55aSTed Kremenek         if (F.FieldChain.size() == 1)
337b89514a9SBenjamin Kramer           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
338d99bd55aSTed Kremenek         else {
339d99bd55aSTed Kremenek           os << " (e.g., via the field chain: '";
340d99bd55aSTed Kremenek           bool first = true;
3410e62c1ccSChris Lattner           for (SmallVectorImpl<const FieldDecl *>::iterator
342d99bd55aSTed Kremenek                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
343d99bd55aSTed Kremenek             if (first)
344d99bd55aSTed Kremenek               first = false;
345d99bd55aSTed Kremenek             else
346d99bd55aSTed Kremenek               os << '.';
347b89514a9SBenjamin Kramer             os << **DI;
348d99bd55aSTed Kremenek           }
349d99bd55aSTed Kremenek           os << "')";
350d99bd55aSTed Kremenek         }
351d99bd55aSTed Kremenek 
352d99bd55aSTed Kremenek         // Generate a report for this bug.
3532f169e7cSArtem Dergachev         auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
354821a3a0fSJordan Rose         R->addRange(ArgRange);
355d99bd55aSTed Kremenek 
356574d78e7SGeorge Karpenkov         if (ArgEx)
357b2cf0063SGeorge Karpenkov           bugreporter::trackExpressionValue(N, ArgEx, *R);
358d99bd55aSTed Kremenek         // FIXME: enhance track back for uninitialized value for arbitrary
359d99bd55aSTed Kremenek         // memregions
3608d3a7a56SAaron Ballman         C.emitReport(std::move(R));
361d99bd55aSTed Kremenek       }
362d99bd55aSTed Kremenek       return true;
363d99bd55aSTed Kremenek     }
364d99bd55aSTed Kremenek   }
365d99bd55aSTed Kremenek 
366d99bd55aSTed Kremenek   return false;
367d99bd55aSTed Kremenek }
368d99bd55aSTed Kremenek 
checkFunctionPointerCall(const CallExpr * CE,CheckerContext & C,ProgramStateRef State) const369eeff1a97SKirstóf Umann ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
370eeff1a97SKirstóf Umann     const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
371eeff1a97SKirstóf Umann 
3723d0d2fefSKirstóf Umann   const Expr *Callee = CE->getCallee()->IgnoreParens();
373632e3b7eSTed Kremenek   const LocationContext *LCtx = C.getLocationContext();
3742995349fSJordan Rose   SVal L = State->getSVal(Callee, LCtx);
375d99bd55aSTed Kremenek 
376d99bd55aSTed Kremenek   if (L.isUndef()) {
3771c8f999eSKirstóf Umann     if (!ChecksEnabled[CK_FunctionPointer]) {
3781c8f999eSKirstóf Umann       C.addSink(State);
3791c8f999eSKirstóf Umann       return nullptr;
3801c8f999eSKirstóf Umann     }
381d99bd55aSTed Kremenek     if (!BT_call_undef)
3824aca9b1cSAlexander Kornienko       BT_call_undef.reset(new BuiltinBug(
3831c8f999eSKirstóf Umann           OriginalName,
3841c8f999eSKirstóf Umann           "Called function pointer is an uninitialized pointer value"));
38592e1449bSJordan Rose     emitBadCall(BT_call_undef.get(), C, Callee);
386eeff1a97SKirstóf Umann     return nullptr;
387d99bd55aSTed Kremenek   }
388d99bd55aSTed Kremenek 
389a01741fcSJordan Rose   ProgramStateRef StNonNull, StNull;
390eeff1a97SKirstóf Umann   std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
391a01741fcSJordan Rose 
392a01741fcSJordan Rose   if (StNull && !StNonNull) {
3931c8f999eSKirstóf Umann     if (!ChecksEnabled[CK_FunctionPointer]) {
3941c8f999eSKirstóf Umann       C.addSink(StNull);
3951c8f999eSKirstóf Umann       return nullptr;
3961c8f999eSKirstóf Umann     }
397d99bd55aSTed Kremenek     if (!BT_call_null)
3984aca9b1cSAlexander Kornienko       BT_call_null.reset(new BuiltinBug(
3991c8f999eSKirstóf Umann           OriginalName, "Called function pointer is null (null dereference)"));
40092e1449bSJordan Rose     emitBadCall(BT_call_null.get(), C, Callee);
401eeff1a97SKirstóf Umann     return nullptr;
402d99bd55aSTed Kremenek   }
40383e4049dSJordan Rose 
404eeff1a97SKirstóf Umann   return StNonNull;
4052995349fSJordan Rose }
406682b3162SJordan Rose 
checkParameterCount(const CallEvent & Call,CheckerContext & C,ProgramStateRef State) const407eeff1a97SKirstóf Umann ProgramStateRef CallAndMessageChecker::checkParameterCount(
408eeff1a97SKirstóf Umann     const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
409eeff1a97SKirstóf Umann 
410eeff1a97SKirstóf Umann   // If we have a function or block declaration, we can make sure we pass
411eeff1a97SKirstóf Umann   // enough parameters.
412eeff1a97SKirstóf Umann   unsigned Params = Call.parameters().size();
413eeff1a97SKirstóf Umann   if (Call.getNumArgs() >= Params)
414eeff1a97SKirstóf Umann     return State;
415eeff1a97SKirstóf Umann 
4161c8f999eSKirstóf Umann   if (!ChecksEnabled[CK_ParameterCount]) {
4171c8f999eSKirstóf Umann     C.addSink(State);
4181c8f999eSKirstóf Umann     return nullptr;
4191c8f999eSKirstóf Umann   }
4201c8f999eSKirstóf Umann 
421eeff1a97SKirstóf Umann   ExplodedNode *N = C.generateErrorNode();
422eeff1a97SKirstóf Umann   if (!N)
423eeff1a97SKirstóf Umann     return nullptr;
424eeff1a97SKirstóf Umann 
425eeff1a97SKirstóf Umann   LazyInit_BT("Function call with too few arguments", BT_call_few_args);
426eeff1a97SKirstóf Umann 
427eeff1a97SKirstóf Umann   SmallString<512> Str;
428eeff1a97SKirstóf Umann   llvm::raw_svector_ostream os(Str);
429eeff1a97SKirstóf Umann   if (isa<AnyFunctionCall>(Call)) {
430eeff1a97SKirstóf Umann     os << "Function ";
431eeff1a97SKirstóf Umann   } else {
432eeff1a97SKirstóf Umann     assert(isa<BlockCall>(Call));
433eeff1a97SKirstóf Umann     os << "Block ";
434eeff1a97SKirstóf Umann   }
435eeff1a97SKirstóf Umann   os << "taking " << Params << " argument" << (Params == 1 ? "" : "s")
436eeff1a97SKirstóf Umann      << " is called with fewer (" << Call.getNumArgs() << ")";
437eeff1a97SKirstóf Umann 
438eeff1a97SKirstóf Umann   C.emitReport(
439eeff1a97SKirstóf Umann       std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
440eeff1a97SKirstóf Umann   return nullptr;
441eeff1a97SKirstóf Umann }
442eeff1a97SKirstóf Umann 
checkCXXMethodCall(const CXXInstanceCall * CC,CheckerContext & C,ProgramStateRef State) const443eeff1a97SKirstóf Umann ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
444eeff1a97SKirstóf Umann     const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {
445eeff1a97SKirstóf Umann 
446faef9cb6STed Kremenek   SVal V = CC->getCXXThisVal();
447faef9cb6STed Kremenek   if (V.isUndef()) {
4481c8f999eSKirstóf Umann     if (!ChecksEnabled[CK_CXXThisMethodCall]) {
4491c8f999eSKirstóf Umann       C.addSink(State);
4501c8f999eSKirstóf Umann       return nullptr;
4511c8f999eSKirstóf Umann     }
452faef9cb6STed Kremenek     if (!BT_cxx_call_undef)
4531c8f999eSKirstóf Umann       BT_cxx_call_undef.reset(new BuiltinBug(
4541c8f999eSKirstóf Umann           OriginalName, "Called C++ object pointer is uninitialized"));
45592e1449bSJordan Rose     emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
456eeff1a97SKirstóf Umann     return nullptr;
457faef9cb6STed Kremenek   }
458a01741fcSJordan Rose 
459a01741fcSJordan Rose   ProgramStateRef StNonNull, StNull;
460eeff1a97SKirstóf Umann   std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
461a01741fcSJordan Rose 
462a01741fcSJordan Rose   if (StNull && !StNonNull) {
4631c8f999eSKirstóf Umann     if (!ChecksEnabled[CK_CXXThisMethodCall]) {
4641c8f999eSKirstóf Umann       C.addSink(StNull);
4651c8f999eSKirstóf Umann       return nullptr;
4661c8f999eSKirstóf Umann     }
467faef9cb6STed Kremenek     if (!BT_cxx_call_null)
4684aca9b1cSAlexander Kornienko       BT_cxx_call_null.reset(
4691c8f999eSKirstóf Umann           new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
47092e1449bSJordan Rose     emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
471eeff1a97SKirstóf Umann     return nullptr;
472faef9cb6STed Kremenek   }
47383e4049dSJordan Rose 
474eeff1a97SKirstóf Umann   return StNonNull;
475faef9cb6STed Kremenek }
476faef9cb6STed Kremenek 
477eeff1a97SKirstóf Umann ProgramStateRef
checkCXXDeallocation(const CXXDeallocatorCall * DC,CheckerContext & C,ProgramStateRef State) const478eeff1a97SKirstóf Umann CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
479eeff1a97SKirstóf Umann                                             CheckerContext &C,
480eeff1a97SKirstóf Umann                                             ProgramStateRef State) const {
4813d0d2fefSKirstóf Umann   const CXXDeleteExpr *DE = DC->getOriginExpr();
4823d0d2fefSKirstóf Umann   assert(DE);
4833d0d2fefSKirstóf Umann   SVal Arg = C.getSVal(DE->getArgument());
484eeff1a97SKirstóf Umann   if (!Arg.isUndef())
485eeff1a97SKirstóf Umann     return State;
486eeff1a97SKirstóf Umann 
4871c8f999eSKirstóf Umann   if (!ChecksEnabled[CK_CXXDeallocationArg]) {
4881c8f999eSKirstóf Umann     C.addSink(State);
4891c8f999eSKirstóf Umann     return nullptr;
4901c8f999eSKirstóf Umann   }
4911c8f999eSKirstóf Umann 
4923d0d2fefSKirstóf Umann   StringRef Desc;
4933d0d2fefSKirstóf Umann   ExplodedNode *N = C.generateErrorNode();
4943d0d2fefSKirstóf Umann   if (!N)
495eeff1a97SKirstóf Umann     return nullptr;
4963d0d2fefSKirstóf Umann   if (!BT_cxx_delete_undef)
4973d0d2fefSKirstóf Umann     BT_cxx_delete_undef.reset(
4981c8f999eSKirstóf Umann         new BuiltinBug(OriginalName, "Uninitialized argument value"));
4993d0d2fefSKirstóf Umann   if (DE->isArrayFormAsWritten())
5003d0d2fefSKirstóf Umann     Desc = "Argument to 'delete[]' is uninitialized";
5013d0d2fefSKirstóf Umann   else
5023d0d2fefSKirstóf Umann     Desc = "Argument to 'delete' is uninitialized";
5033d0d2fefSKirstóf Umann   BugType *BT = BT_cxx_delete_undef.get();
5043d0d2fefSKirstóf Umann   auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
5053d0d2fefSKirstóf Umann   bugreporter::trackExpressionValue(N, DE, *R);
5063d0d2fefSKirstóf Umann   C.emitReport(std::move(R));
507eeff1a97SKirstóf Umann   return nullptr;
5083d0d2fefSKirstóf Umann }
509eeff1a97SKirstóf Umann 
checkArgInitializedness(const CallEvent & Call,CheckerContext & C,ProgramStateRef State) const510eeff1a97SKirstóf Umann ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
511eeff1a97SKirstóf Umann     const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
512eeff1a97SKirstóf Umann 
513eeff1a97SKirstóf Umann   const Decl *D = Call.getDecl();
5143d0d2fefSKirstóf Umann 
515682b3162SJordan Rose   // Don't check for uninitialized field values in arguments if the
516682b3162SJordan Rose   // caller has a body that is available and we have the chance to inline it.
517682b3162SJordan Rose   // This is a hack, but is a reasonable compromise betweens sometimes warning
518682b3162SJordan Rose   // and sometimes not depending on if we decide to inline a function.
519682b3162SJordan Rose   const bool checkUninitFields =
520faef9cb6STed Kremenek       !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
521682b3162SJordan Rose 
522b8984329SAhmed Charles   std::unique_ptr<BugType> *BT;
523627b046cSJordan Rose   if (isa<ObjCMethodCall>(Call))
524682b3162SJordan Rose     BT = &BT_msg_arg;
525627b046cSJordan Rose   else
526682b3162SJordan Rose     BT = &BT_call_arg;
527682b3162SJordan Rose 
5288693adfdSDevin Coughlin   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
529821a3a0fSJordan Rose   for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
5300dbb783cSCraig Topper     const ParmVarDecl *ParamDecl = nullptr;
531821a3a0fSJordan Rose     if (FD && i < FD->getNumParams())
532821a3a0fSJordan Rose       ParamDecl = FD->getParamDecl(i);
533627b046cSJordan Rose     if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
5343d0d2fefSKirstóf Umann                            Call.getArgExpr(i), i, checkUninitFields, Call, *BT,
5353d0d2fefSKirstóf Umann                            ParamDecl))
536eeff1a97SKirstóf Umann       return nullptr;
537821a3a0fSJordan Rose   }
538eeff1a97SKirstóf Umann   return State;
539eeff1a97SKirstóf Umann }
540eeff1a97SKirstóf Umann 
checkPreCall(const CallEvent & Call,CheckerContext & C) const541eeff1a97SKirstóf Umann void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
542eeff1a97SKirstóf Umann                                          CheckerContext &C) const {
543eeff1a97SKirstóf Umann   ProgramStateRef State = C.getState();
544eeff1a97SKirstóf Umann 
545eeff1a97SKirstóf Umann   if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))
546eeff1a97SKirstóf Umann     State = checkFunctionPointerCall(CE, C, State);
547eeff1a97SKirstóf Umann 
548eeff1a97SKirstóf Umann   if (!State)
549eeff1a97SKirstóf Umann     return;
550eeff1a97SKirstóf Umann 
551eeff1a97SKirstóf Umann   if (Call.getDecl())
552eeff1a97SKirstóf Umann     State = checkParameterCount(Call, C, State);
553eeff1a97SKirstóf Umann 
554eeff1a97SKirstóf Umann   if (!State)
555eeff1a97SKirstóf Umann     return;
556eeff1a97SKirstóf Umann 
557eeff1a97SKirstóf Umann   if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))
558eeff1a97SKirstóf Umann     State = checkCXXMethodCall(CC, C, State);
559eeff1a97SKirstóf Umann 
560eeff1a97SKirstóf Umann   if (!State)
561eeff1a97SKirstóf Umann     return;
562eeff1a97SKirstóf Umann 
563eeff1a97SKirstóf Umann   if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))
564eeff1a97SKirstóf Umann     State = checkCXXDeallocation(DC, C, State);
565eeff1a97SKirstóf Umann 
566eeff1a97SKirstóf Umann   if (!State)
567eeff1a97SKirstóf Umann     return;
568eeff1a97SKirstóf Umann 
569eeff1a97SKirstóf Umann   State = checkArgInitializedness(Call, C, State);
57083e4049dSJordan Rose 
57183e4049dSJordan Rose   // If we make it here, record our assumptions about the callee.
57283e4049dSJordan Rose   C.addTransition(State);
573d99bd55aSTed Kremenek }
574d99bd55aSTed Kremenek 
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const575547060b3SJordan Rose void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
5766d6801c5SArgyrios Kyrtzidis                                                 CheckerContext &C) const {
577547060b3SJordan Rose   SVal recVal = msg.getReceiverSVal();
5786d6801c5SArgyrios Kyrtzidis   if (recVal.isUndef()) {
5791c8f999eSKirstóf Umann     if (!ChecksEnabled[CK_UndefReceiver]) {
5801c8f999eSKirstóf Umann       C.addSink();
5811c8f999eSKirstóf Umann       return;
5821c8f999eSKirstóf Umann     }
583e39bd407SDevin Coughlin     if (ExplodedNode *N = C.generateErrorNode()) {
5840dbb783cSCraig Topper       BugType *BT = nullptr;
585627b046cSJordan Rose       switch (msg.getMessageKind()) {
586627b046cSJordan Rose       case OCM_Message:
587d99bd55aSTed Kremenek         if (!BT_msg_undef)
5881c8f999eSKirstóf Umann           BT_msg_undef.reset(new BuiltinBug(OriginalName,
5894aca9b1cSAlexander Kornienko                                             "Receiver in message expression "
590e98d63a8STed Kremenek                                             "is an uninitialized value"));
591e98d63a8STed Kremenek         BT = BT_msg_undef.get();
592627b046cSJordan Rose         break;
593627b046cSJordan Rose       case OCM_PropertyAccess:
594627b046cSJordan Rose         if (!BT_objc_prop_undef)
5954aca9b1cSAlexander Kornienko           BT_objc_prop_undef.reset(new BuiltinBug(
5961c8f999eSKirstóf Umann               OriginalName,
5971c8f999eSKirstóf Umann               "Property access on an uninitialized object pointer"));
598627b046cSJordan Rose         BT = BT_objc_prop_undef.get();
599627b046cSJordan Rose         break;
600627b046cSJordan Rose       case OCM_Subscript:
601627b046cSJordan Rose         if (!BT_objc_subscript_undef)
6024aca9b1cSAlexander Kornienko           BT_objc_subscript_undef.reset(new BuiltinBug(
6031c8f999eSKirstóf Umann               OriginalName,
6041c8f999eSKirstóf Umann               "Subscript access on an uninitialized object pointer"));
605627b046cSJordan Rose         BT = BT_objc_subscript_undef.get();
606627b046cSJordan Rose         break;
607e98d63a8STed Kremenek       }
608627b046cSJordan Rose       assert(BT && "Unknown message kind.");
609627b046cSJordan Rose 
61072649423SKristof Umann       auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
611627b046cSJordan Rose       const ObjCMessageExpr *ME = msg.getOriginExpr();
612627b046cSJordan Rose       R->addRange(ME->getReceiverRange());
613547060b3SJordan Rose 
614547060b3SJordan Rose       // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
615627b046cSJordan Rose       if (const Expr *ReceiverE = ME->getInstanceReceiver())
616b2cf0063SGeorge Karpenkov         bugreporter::trackExpressionValue(N, ReceiverE, *R);
6178d3a7a56SAaron Ballman       C.emitReport(std::move(R));
618d99bd55aSTed Kremenek     }
619d99bd55aSTed Kremenek     return;
6206d6801c5SArgyrios Kyrtzidis   }
6216d6801c5SArgyrios Kyrtzidis }
622ca5ab2b0SDevin Coughlin 
checkObjCMessageNil(const ObjCMethodCall & msg,CheckerContext & C) const623ca5ab2b0SDevin Coughlin void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
624ca5ab2b0SDevin Coughlin                                                 CheckerContext &C) const {
625ca5ab2b0SDevin Coughlin   HandleNilReceiver(C, C.getState(), msg);
626d99bd55aSTed Kremenek }
627d99bd55aSTed Kremenek 
emitNilReceiverBug(CheckerContext & C,const ObjCMethodCall & msg,ExplodedNode * N) const628d99bd55aSTed Kremenek void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
629547060b3SJordan Rose                                                const ObjCMethodCall &msg,
6306d6801c5SArgyrios Kyrtzidis                                                ExplodedNode *N) const {
6311c8f999eSKirstóf Umann   if (!ChecksEnabled[CK_NilReceiver]) {
6321c8f999eSKirstóf Umann     C.addSink();
6331c8f999eSKirstóf Umann     return;
6341c8f999eSKirstóf Umann   }
635d99bd55aSTed Kremenek 
636d99bd55aSTed Kremenek   if (!BT_msg_ret)
6371c8f999eSKirstóf Umann     BT_msg_ret.reset(new BuiltinBug(OriginalName,
6381c8f999eSKirstóf Umann                                     "Receiver in message expression is 'nil'"));
639d99bd55aSTed Kremenek 
640627b046cSJordan Rose   const ObjCMessageExpr *ME = msg.getOriginExpr();
641627b046cSJordan Rose 
642c610bcacSAnna Zaks   QualType ResTy = msg.getResultType();
643c610bcacSAnna Zaks 
6442c1dd271SDylan Noblesmith   SmallString<200> buf;
645d99bd55aSTed Kremenek   llvm::raw_svector_ostream os(buf);
646b190f974SAaron Ballman   os << "The receiver of message '";
647b190f974SAaron Ballman   ME->getSelector().print(os);
648b190f974SAaron Ballman   os << "' is nil";
649c610bcacSAnna Zaks   if (ResTy->isReferenceType()) {
650c610bcacSAnna Zaks     os << ", which results in forming a null reference";
651c610bcacSAnna Zaks   } else {
652c610bcacSAnna Zaks     os << " and returns a value of type '";
653547060b3SJordan Rose     msg.getResultType().print(os, C.getLangOpts());
654547060b3SJordan Rose     os << "' that will be garbage";
655c610bcacSAnna Zaks   }
656d99bd55aSTed Kremenek 
6572f169e7cSArtem Dergachev   auto report =
6582f169e7cSArtem Dergachev       std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
659627b046cSJordan Rose   report->addRange(ME->getReceiverRange());
660547060b3SJordan Rose   // FIXME: This won't track "self" in messages to super.
661627b046cSJordan Rose   if (const Expr *receiver = ME->getInstanceReceiver()) {
662b2cf0063SGeorge Karpenkov     bugreporter::trackExpressionValue(N, receiver, *report);
663d99bd55aSTed Kremenek   }
6648d3a7a56SAaron Ballman   C.emitReport(std::move(report));
665d99bd55aSTed Kremenek }
666d99bd55aSTed Kremenek 
supportsNilWithFloatRet(const llvm::Triple & triple)667d99bd55aSTed Kremenek static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
668c3337493SBob Wilson   return (triple.getVendor() == llvm::Triple::Apple &&
6696f3ff22eSTim Northover           (triple.isiOS() || triple.isWatchOS() ||
6706f3ff22eSTim Northover            !triple.isMacOSXVersionLT(10,5)));
671d99bd55aSTed Kremenek }
672d99bd55aSTed Kremenek 
HandleNilReceiver(CheckerContext & C,ProgramStateRef state,const ObjCMethodCall & Msg) const673d99bd55aSTed Kremenek void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
67449b1e38eSTed Kremenek                                               ProgramStateRef state,
675547060b3SJordan Rose                                               const ObjCMethodCall &Msg) const {
67637ab726dSArgyrios Kyrtzidis   ASTContext &Ctx = C.getASTContext();
6776a619222SAnton Yartsev   static CheckerProgramPointTag Tag(this, "NilReceiver");
678d99bd55aSTed Kremenek 
679d99bd55aSTed Kremenek   // Check the return type of the message expression.  A message to nil will
680d99bd55aSTed Kremenek   // return different values depending on the return type and the architecture.
681547060b3SJordan Rose   QualType RetTy = Msg.getResultType();
682d99bd55aSTed Kremenek   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
683632e3b7eSTed Kremenek   const LocationContext *LCtx = C.getLocationContext();
684d99bd55aSTed Kremenek 
685d99bd55aSTed Kremenek   if (CanRetTy->isStructureOrClassType()) {
686a98358eaSTed Kremenek     // Structure returns are safe since the compiler zeroes them out.
687547060b3SJordan Rose     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
68822fa6eccSAnna Zaks     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
689d99bd55aSTed Kremenek     return;
690d99bd55aSTed Kremenek   }
691d99bd55aSTed Kremenek 
692a98358eaSTed Kremenek   // Other cases: check if sizeof(return type) > sizeof(void*)
6931c887b35SAnna Zaks   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
694547060b3SJordan Rose                                   .isConsumedExpr(Msg.getOriginExpr())) {
695d99bd55aSTed Kremenek     // Compute: sizeof(void *) and sizeof(return type)
696d99bd55aSTed Kremenek     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
697d99bd55aSTed Kremenek     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
698d99bd55aSTed Kremenek 
699c610bcacSAnna Zaks     if (CanRetTy.getTypePtr()->isReferenceType()||
700c610bcacSAnna Zaks         (voidPtrSize < returnTypeSize &&
701e8bbc121SDouglas Gregor          !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
702d99bd55aSTed Kremenek            (Ctx.FloatTy == CanRetTy ||
703d99bd55aSTed Kremenek             Ctx.DoubleTy == CanRetTy ||
704d99bd55aSTed Kremenek             Ctx.LongDoubleTy == CanRetTy ||
705d99bd55aSTed Kremenek             Ctx.LongLongTy == CanRetTy ||
706c610bcacSAnna Zaks             Ctx.UnsignedLongLongTy == CanRetTy)))) {
707e39bd407SDevin Coughlin       if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
708547060b3SJordan Rose         emitNilReceiverBug(C, Msg, N);
709d99bd55aSTed Kremenek       return;
710d99bd55aSTed Kremenek     }
711d99bd55aSTed Kremenek 
712d99bd55aSTed Kremenek     // Handle the safe cases where the return value is 0 if the
713d99bd55aSTed Kremenek     // receiver is nil.
714d99bd55aSTed Kremenek     //
715d99bd55aSTed Kremenek     // FIXME: For now take the conservative approach that we only
716d99bd55aSTed Kremenek     // return null values if we *know* that the receiver is nil.
717d99bd55aSTed Kremenek     // This is because we can have surprises like:
718d99bd55aSTed Kremenek     //
719d99bd55aSTed Kremenek     //   ... = [[NSScreens screens] objectAtIndex:0];
720d99bd55aSTed Kremenek     //
721d99bd55aSTed Kremenek     // What can happen is that [... screens] could return nil, but
722d99bd55aSTed Kremenek     // it most likely isn't nil.  We should assume the semantics
723d99bd55aSTed Kremenek     // of this case unless we have *a lot* more knowledge.
724d99bd55aSTed Kremenek     //
725547060b3SJordan Rose     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
72622fa6eccSAnna Zaks     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
727d99bd55aSTed Kremenek     return;
728d99bd55aSTed Kremenek   }
729d99bd55aSTed Kremenek 
730da4c8d68SAnna Zaks   C.addTransition(state);
731d99bd55aSTed Kremenek }
7326d6801c5SArgyrios Kyrtzidis 
registerCallAndMessageModeling(CheckerManager & mgr)7331c8f999eSKirstóf Umann void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
7348fd74ebfSKristof Umann   mgr.registerChecker<CallAndMessageChecker>();
7356d6801c5SArgyrios Kyrtzidis }
736821a3a0fSJordan Rose 
shouldRegisterCallAndMessageModeling(const CheckerManager & mgr)7371c8f999eSKirstóf Umann bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
7381c8f999eSKirstóf Umann   return true;
7391c8f999eSKirstóf Umann }
7401c8f999eSKirstóf Umann 
registerCallAndMessageChecker(CheckerManager & mgr)7411c8f999eSKirstóf Umann void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
7421c8f999eSKirstóf Umann   CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
7431c8f999eSKirstóf Umann 
7441c8f999eSKirstóf Umann   checker->OriginalName = mgr.getCurrentCheckerName();
7451c8f999eSKirstóf Umann 
7461c8f999eSKirstóf Umann #define QUERY_CHECKER_OPTION(OPTION)                                           \
7471c8f999eSKirstóf Umann   checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] =                 \
7481c8f999eSKirstóf Umann       mgr.getAnalyzerOptions().getCheckerBooleanOption(                        \
7491c8f999eSKirstóf Umann           mgr.getCurrentCheckerName(), #OPTION);
7501c8f999eSKirstóf Umann 
7511c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(FunctionPointer)
7521c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(ParameterCount)
7531c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(CXXThisMethodCall)
7541c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(CXXDeallocationArg)
7551c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(ArgInitializedness)
7561c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
7571c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(NilReceiver)
7581c8f999eSKirstóf Umann   QUERY_CHECKER_OPTION(UndefReceiver)
7591c8f999eSKirstóf Umann }
7601c8f999eSKirstóf Umann 
shouldRegisterCallAndMessageChecker(const CheckerManager & mgr)761bda3dd0dSKirstóf Umann bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
7628fd74ebfSKristof Umann   return true;
7638fd74ebfSKristof Umann }
764