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