clang: lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
46#include "llvm/Support/raw_ostream.h"
47
48using namespace clang;
49using namespace ento;
50
55
56namespace {
57class ObjCSelfInitChecker : public Checker< check::PostObjCMessage,
58 check::PostStmt,
59 check::PreStmt,
60 check::PreCall,
61 check::PostCall,
62 check::Location,
63 check::Bind > {
64 const BugType BT{this, "Missing \"self = [(super or self) init...]\"",
66
67 void checkForInvalidSelf(const Expr *E, CheckerContext &C,
68 const char *errorStr) const;
69
70public:
71 void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const;
72 void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
73 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
74 void checkLocation(SVal location, bool isLoad, const Stmt *S,
75 CheckerContext &C) const;
76 void checkBind(SVal loc, SVal val, const Stmt *S, bool AtDeclInit,
77 CheckerContext &C) const;
78
79 void checkPreCall(const CallEvent &CE, CheckerContext &C) const;
80 void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
81
83 const char *NL, const char *Sep) const override;
84};
85}
86
87namespace {
88enum SelfFlagEnum {
89
90 SelfFlag_None = 0x0,
91
92 SelfFlag_Self = 0x1,
93
94 SelfFlag_InitRes = 0x2
95};
96}
97
100
101
102
103
104
106
108 if (SymbolRef sym = val.getAsSymbol())
109 if (const SelfFlagEnum *attachedFlags = state->get(sym))
110 return *attachedFlags;
111 return SelfFlag_None;
112}
113
117
120
122 state = state->set(sym,
123 SelfFlagEnum(getSelfFlags(val, state) | flag));
124 C.addTransition(state);
125 }
126}
127
131
132
133
134
136 SVal exprVal = C.getSVal(E);
138 return false;
139 if (hasSelfFlag(exprVal, SelfFlag_InitRes, C))
140 return false;
141
142 return true;
143}
144
145void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
146 const char *errorStr) const {
147 if (!E)
148 return;
149
150 if (.getState()->get())
151 return;
152
154 return;
155
156
157 ExplodedNode *N = C.generateErrorNode();
158 if (!N)
159 return;
160
161 C.emitReport(std::make_unique(BT, errorStr, N));
162}
163
164void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
165 CheckerContext &C) const {
166
167
168
169
170
172 C.getCurrentAnalysisDeclContext()->getDecl())))
173 return;
174
176
178
179
180
181
182 state = state->set(true);
183
186 return;
187 }
188
189
190
191
192
193}
194
195void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
196 CheckerContext &C) const {
197
199 C.getCurrentAnalysisDeclContext()->getDecl())))
200 return;
201
202 checkForInvalidSelf(
204 "Instance variable used while 'self' is not set to the result of "
205 "'[(super or self) init...]'");
206}
207
208void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
209 CheckerContext &C) const {
210
212 C.getCurrentAnalysisDeclContext()->getDecl())))
213 return;
214
216 "Returning 'self' while it is not set to the result of "
217 "'[(super or self) init...]'");
218}
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236void ObjCSelfInitChecker::checkPreCall(const CallEvent &CE,
237 CheckerContext &C) const {
238
240 C.getCurrentAnalysisDeclContext()->getDecl())))
241 return;
242
245
246
247
248
249
250 for (unsigned i = 0; i < NumArgs; ++i) {
253 SelfFlagEnum selfFlags =
255 C.addTransition(state->set(selfFlags));
256 return;
257 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
259 C.addTransition(state->set(selfFlags));
260 return;
261 }
262 }
263}
264
265void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
266 CheckerContext &C) const {
267
269 C.getCurrentAnalysisDeclContext()->getDecl())))
270 return;
271
273 SelfFlagEnum prevFlags = state->get();
274 if (!prevFlags)
275 return;
276 state = state->remove();
277
279 for (unsigned i = 0; i < NumArgs; ++i) {
282
283
284
285 addSelfFlag(state, state->getSVal(argV.castAs()), prevFlags, C);
286 return;
287 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
288
289
290
291
293 return;
294 }
295 }
296
297 C.addTransition(state);
298}
299
300void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
301 const Stmt *S,
302 CheckerContext &C) const {
304 C.getCurrentAnalysisDeclContext()->getDecl())))
305 return;
306
307
308
311 addSelfFlag(state, state->getSVal(location.castAs()), SelfFlag_Self,
312 C);
313}
314
315void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
316 bool AtDeclInit, CheckerContext &C) const {
317
318
319
320
321
326
327
329 State = State->remove();
331 State = State->remove(sym);
332 C.addTransition(State);
333 }
334}
335
336void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State,
337 const char *NL, const char *Sep) const {
338 SelfFlagTy FlagMap = State->get();
339 bool DidCallInit = State->get();
340 SelfFlagEnum PreCallFlags = State->get();
341
342 if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
343 return;
344
345 Out << Sep << NL << "ObjCSelfInitChecker:" << NL;
346
347 if (DidCallInit)
348 Out << " An init method has been called." << NL;
349
350 if (PreCallFlags != SelfFlag_None) {
351 if (PreCallFlags & SelfFlag_Self) {
352 Out << " An argument of the current call came from the 'self' variable."
353 << NL;
354 }
355 if (PreCallFlags & SelfFlag_InitRes) {
356 Out << " An argument of the current call came from an init method."
357 << NL;
358 }
359 }
360
361 Out << NL;
362 for (auto [Sym, Flag] : FlagMap) {
363 Out << Sym << " : ";
364
365 if (Flag == SelfFlag_None)
366 Out << "none";
367
368 if (Flag & SelfFlag_Self)
369 Out << "self variable";
370
371 if (Flag & SelfFlag_InitRes) {
372 if (Flag != SelfFlag_InitRes)
373 Out << " | ";
374 Out << "result of init method";
375 }
376
377 Out << NL;
378 }
379}
380
381
382
384 if (!ND)
385 return false;
386
387 const ObjCMethodDecl *MD = dyn_cast(ND);
388 if (!MD)
389 return false;
391 return false;
392
393
394
398 for ( ; ID ; ID = ID->getSuperClass()) {
400
401 if (II == NSObjectII)
402 break;
403 }
404 return ID != nullptr;
405}
406
407
411 return false;
413 return false;
414
417 return (DR->getDecl() == analCtx->getSelfDecl());
418
419 return false;
420}
421
425
429
430
431
432
433
434void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
436}
437
438bool ento::shouldRegisterObjCSelfInitChecker(const CheckerManager &mgr) {
439 return true;
440}
static bool isInitMessage(const ObjCMethodCall &Msg)
Definition ObjCSelfInitChecker.cpp:426
static bool isSelfVar(SVal location, CheckerContext &C)
Returns true if the location is 'self'.
Definition ObjCSelfInitChecker.cpp:408
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)
Definition ObjCSelfInitChecker.cpp:383
static bool isInitializationMethod(const ObjCMethodDecl *MD)
Definition ObjCSelfInitChecker.cpp:422
static bool isInvalidSelf(const Expr *E, CheckerContext &C)
Returns true of the value of the expression is the object that 'self' points to and is an object that...
Definition ObjCSelfInitChecker.cpp:135
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)
A call receiving a reference to 'self' invalidates the object that 'self' contains.
Definition ObjCSelfInitChecker.cpp:107
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C)
Definition ObjCSelfInitChecker.cpp:128
static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C)
Definition ObjCSelfInitChecker.cpp:118
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
const ImplicitParamDecl * getSelfDecl() const
ASTContext & getASTContext() const LLVM_READONLY
This represents one expression.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
This represents a decl that may have a name.
Represents an ObjC class declaration.
ObjCInterfaceDecl * getSuperClass() const
const Expr * getBase() const
ObjCMethodDecl - Represents an instance or class method declaration.
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
ObjCInterfaceDecl * getClassInterface()
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SVal getReturnValue() const
Returns the return value of the call.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Represents any expression that calls an Objective-C method.
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * stripCasts(bool StripBaseCasts=true) const
Get the underlining region and strip casts.
const char *const CoreFoundationObjectiveC
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))