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