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