File: | tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp |
Warning: | line 122, column 13 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //== ObjCSelfInitChecker.cpp - Checker for 'self' initialization -*- C++ -*--=// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This defines ObjCSelfInitChecker, a builtin check that checks for uses of | |||
11 | // 'self' before proper initialization. | |||
12 | // | |||
13 | //===----------------------------------------------------------------------===// | |||
14 | ||||
15 | // This checks initialization methods to verify that they assign 'self' to the | |||
16 | // result of an initialization call (e.g. [super init], or [self initWith..]) | |||
17 | // before using 'self' or any instance variable. | |||
18 | // | |||
19 | // To perform the required checking, values are tagged with flags that indicate | |||
20 | // 1) if the object is the one pointed to by 'self', and 2) if the object | |||
21 | // is the result of an initializer (e.g. [super init]). | |||
22 | // | |||
23 | // Uses of an object that is true for 1) but not 2) trigger a diagnostic. | |||
24 | // The uses that are currently checked are: | |||
25 | // - Using instance variables. | |||
26 | // - Returning the object. | |||
27 | // | |||
28 | // Note that we don't check for an invalid 'self' that is the receiver of an | |||
29 | // obj-c message expression to cut down false positives where logging functions | |||
30 | // get information from self (like its class) or doing "invalidation" on self | |||
31 | // when the initialization fails. | |||
32 | // | |||
33 | // Because the object that 'self' points to gets invalidated when a call | |||
34 | // receives a reference to 'self', the checker keeps track and passes the flags | |||
35 | // for 1) and 2) to the new object that 'self' points to after the call. | |||
36 | // | |||
37 | //===----------------------------------------------------------------------===// | |||
38 | ||||
39 | #include "ClangSACheckers.h" | |||
40 | #include "clang/AST/ParentMap.h" | |||
41 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | |||
42 | #include "clang/StaticAnalyzer/Core/Checker.h" | |||
43 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" | |||
44 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | |||
45 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | |||
46 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" | |||
47 | #include "llvm/Support/raw_ostream.h" | |||
48 | ||||
49 | using namespace clang; | |||
50 | using namespace ento; | |||
51 | ||||
52 | static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND); | |||
53 | static bool isInitializationMethod(const ObjCMethodDecl *MD); | |||
54 | static bool isInitMessage(const ObjCMethodCall &Msg); | |||
55 | static bool isSelfVar(SVal location, CheckerContext &C); | |||
56 | ||||
57 | namespace { | |||
58 | class ObjCSelfInitChecker : public Checker< check::PostObjCMessage, | |||
59 | check::PostStmt<ObjCIvarRefExpr>, | |||
60 | check::PreStmt<ReturnStmt>, | |||
61 | check::PreCall, | |||
62 | check::PostCall, | |||
63 | check::Location, | |||
64 | check::Bind > { | |||
65 | mutable std::unique_ptr<BugType> BT; | |||
66 | ||||
67 | void checkForInvalidSelf(const Expr *E, CheckerContext &C, | |||
68 | const char *errorStr) const; | |||
69 | ||||
70 | public: | |||
71 | ObjCSelfInitChecker() {} | |||
72 | void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const; | |||
73 | void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const; | |||
74 | void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; | |||
75 | void checkLocation(SVal location, bool isLoad, const Stmt *S, | |||
76 | CheckerContext &C) const; | |||
77 | void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; | |||
78 | ||||
79 | void checkPreCall(const CallEvent &CE, CheckerContext &C) const; | |||
80 | void checkPostCall(const CallEvent &CE, CheckerContext &C) const; | |||
81 | ||||
82 | void printState(raw_ostream &Out, ProgramStateRef State, | |||
83 | const char *NL, const char *Sep) const override; | |||
84 | }; | |||
85 | } // end anonymous namespace | |||
86 | ||||
87 | namespace { | |||
88 | enum SelfFlagEnum { | |||
89 | /// \brief No flag set. | |||
90 | SelfFlag_None = 0x0, | |||
91 | /// \brief Value came from 'self'. | |||
92 | SelfFlag_Self = 0x1, | |||
93 | /// \brief Value came from the result of an initializer (e.g. [super init]). | |||
94 | SelfFlag_InitRes = 0x2 | |||
95 | }; | |||
96 | } | |||
97 | ||||
98 | REGISTER_MAP_WITH_PROGRAMSTATE(SelfFlag, SymbolRef, unsigned)namespace { class SelfFlag {}; using SelfFlagTy = llvm::ImmutableMap <SymbolRef, unsigned>; } namespace clang { namespace ento { template <> struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlagTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } | |||
99 | REGISTER_TRAIT_WITH_PROGRAMSTATE(CalledInit, bool)namespace { class CalledInit {}; using CalledInitTy = bool; } namespace clang { namespace ento { template <> struct ProgramStateTrait <CalledInit> : public ProgramStatePartialTrait<CalledInitTy > { static void *GDMIndex() { static int Index; return & Index; } }; } } | |||
100 | ||||
101 | /// \brief A call receiving a reference to 'self' invalidates the object that | |||
102 | /// 'self' contains. This keeps the "self flags" assigned to the 'self' | |||
103 | /// object before the call so we can assign them to the new object that 'self' | |||
104 | /// points to after the call. | |||
105 | REGISTER_TRAIT_WITH_PROGRAMSTATE(PreCallSelfFlags, unsigned)namespace { class PreCallSelfFlags {}; using PreCallSelfFlagsTy = unsigned; } namespace clang { namespace ento { template < > struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<PreCallSelfFlagsTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } | |||
106 | ||||
107 | static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) { | |||
108 | if (SymbolRef sym = val.getAsSymbol()) | |||
109 | if (const unsigned *attachedFlags = state->get<SelfFlag>(sym)) | |||
110 | return (SelfFlagEnum)*attachedFlags; | |||
111 | return SelfFlag_None; | |||
112 | } | |||
113 | ||||
114 | static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) { | |||
115 | return getSelfFlags(val, C.getState()); | |||
116 | } | |||
117 | ||||
118 | static void addSelfFlag(ProgramStateRef state, SVal val, | |||
119 | SelfFlagEnum flag, CheckerContext &C) { | |||
120 | // We tag the symbol that the SVal wraps. | |||
121 | if (SymbolRef sym = val.getAsSymbol()) { | |||
122 | state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag); | |||
| ||||
123 | C.addTransition(state); | |||
124 | } | |||
125 | } | |||
126 | ||||
127 | static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) { | |||
128 | return getSelfFlags(val, C) & flag; | |||
129 | } | |||
130 | ||||
131 | /// \brief Returns true of the value of the expression is the object that 'self' | |||
132 | /// points to and is an object that did not come from the result of calling | |||
133 | /// an initializer. | |||
134 | static bool isInvalidSelf(const Expr *E, CheckerContext &C) { | |||
135 | SVal exprVal = C.getSVal(E); | |||
136 | if (!hasSelfFlag(exprVal, SelfFlag_Self, C)) | |||
137 | return false; // value did not come from 'self'. | |||
138 | if (hasSelfFlag(exprVal, SelfFlag_InitRes, C)) | |||
139 | return false; // 'self' is properly initialized. | |||
140 | ||||
141 | return true; | |||
142 | } | |||
143 | ||||
144 | void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C, | |||
145 | const char *errorStr) const { | |||
146 | if (!E) | |||
147 | return; | |||
148 | ||||
149 | if (!C.getState()->get<CalledInit>()) | |||
150 | return; | |||
151 | ||||
152 | if (!isInvalidSelf(E, C)) | |||
153 | return; | |||
154 | ||||
155 | // Generate an error node. | |||
156 | ExplodedNode *N = C.generateErrorNode(); | |||
157 | if (!N) | |||
158 | return; | |||
159 | ||||
160 | if (!BT) | |||
161 | BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"", | |||
162 | categories::CoreFoundationObjectiveC)); | |||
163 | C.emitReport(llvm::make_unique<BugReport>(*BT, errorStr, N)); | |||
164 | } | |||
165 | ||||
166 | void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, | |||
167 | CheckerContext &C) const { | |||
168 | // When encountering a message that does initialization (init rule), | |||
169 | // tag the return value so that we know later on that if self has this value | |||
170 | // then it is properly initialized. | |||
171 | ||||
172 | // FIXME: A callback should disable checkers at the start of functions. | |||
173 | if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( | |||
174 | C.getCurrentAnalysisDeclContext()->getDecl()))) | |||
175 | return; | |||
176 | ||||
177 | if (isInitMessage(Msg)) { | |||
178 | // Tag the return value as the result of an initializer. | |||
179 | ProgramStateRef state = C.getState(); | |||
180 | ||||
181 | // FIXME this really should be context sensitive, where we record | |||
182 | // the current stack frame (for IPA). Also, we need to clean this | |||
183 | // value out when we return from this method. | |||
184 | state = state->set<CalledInit>(true); | |||
185 | ||||
186 | SVal V = C.getSVal(Msg.getOriginExpr()); | |||
187 | addSelfFlag(state, V, SelfFlag_InitRes, C); | |||
188 | return; | |||
189 | } | |||
190 | ||||
191 | // We don't check for an invalid 'self' in an obj-c message expression to cut | |||
192 | // down false positives where logging functions get information from self | |||
193 | // (like its class) or doing "invalidation" on self when the initialization | |||
194 | // fails. | |||
195 | } | |||
196 | ||||
197 | void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E, | |||
198 | CheckerContext &C) const { | |||
199 | // FIXME: A callback should disable checkers at the start of functions. | |||
200 | if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( | |||
201 | C.getCurrentAnalysisDeclContext()->getDecl()))) | |||
202 | return; | |||
203 | ||||
204 | checkForInvalidSelf( | |||
205 | E->getBase(), C, | |||
206 | "Instance variable used while 'self' is not set to the result of " | |||
207 | "'[(super or self) init...]'"); | |||
208 | } | |||
209 | ||||
210 | void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, | |||
211 | CheckerContext &C) const { | |||
212 | // FIXME: A callback should disable checkers at the start of functions. | |||
213 | if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( | |||
214 | C.getCurrentAnalysisDeclContext()->getDecl()))) | |||
215 | return; | |||
216 | ||||
217 | checkForInvalidSelf(S->getRetValue(), C, | |||
218 | "Returning 'self' while it is not set to the result of " | |||
219 | "'[(super or self) init...]'"); | |||
220 | } | |||
221 | ||||
222 | // When a call receives a reference to 'self', [Pre/Post]Call pass | |||
223 | // the SelfFlags from the object 'self' points to before the call to the new | |||
224 | // object after the call. This is to avoid invalidation of 'self' by logging | |||
225 | // functions. | |||
226 | // Another common pattern in classes with multiple initializers is to put the | |||
227 | // subclass's common initialization bits into a static function that receives | |||
228 | // the value of 'self', e.g: | |||
229 | // @code | |||
230 | // if (!(self = [super init])) | |||
231 | // return nil; | |||
232 | // if (!(self = _commonInit(self))) | |||
233 | // return nil; | |||
234 | // @endcode | |||
235 | // Until we can use inter-procedural analysis, in such a call, transfer the | |||
236 | // SelfFlags to the result of the call. | |||
237 | ||||
238 | void ObjCSelfInitChecker::checkPreCall(const CallEvent &CE, | |||
239 | CheckerContext &C) const { | |||
240 | // FIXME: A callback should disable checkers at the start of functions. | |||
241 | if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( | |||
242 | C.getCurrentAnalysisDeclContext()->getDecl()))) | |||
243 | return; | |||
244 | ||||
245 | ProgramStateRef state = C.getState(); | |||
246 | unsigned NumArgs = CE.getNumArgs(); | |||
247 | // If we passed 'self' as and argument to the call, record it in the state | |||
248 | // to be propagated after the call. | |||
249 | // Note, we could have just given up, but try to be more optimistic here and | |||
250 | // assume that the functions are going to continue initialization or will not | |||
251 | // modify self. | |||
252 | for (unsigned i = 0; i < NumArgs; ++i) { | |||
253 | SVal argV = CE.getArgSVal(i); | |||
254 | if (isSelfVar(argV, C)) { | |||
255 | unsigned selfFlags = getSelfFlags(state->getSVal(argV.castAs<Loc>()), C); | |||
256 | C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); | |||
257 | return; | |||
258 | } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { | |||
259 | unsigned selfFlags = getSelfFlags(argV, C); | |||
260 | C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); | |||
261 | return; | |||
262 | } | |||
263 | } | |||
264 | } | |||
265 | ||||
266 | void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE, | |||
267 | CheckerContext &C) const { | |||
268 | // FIXME: A callback should disable checkers at the start of functions. | |||
269 | if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( | |||
270 | C.getCurrentAnalysisDeclContext()->getDecl()))) | |||
271 | return; | |||
272 | ||||
273 | ProgramStateRef state = C.getState(); | |||
274 | SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>(); | |||
275 | if (!prevFlags) | |||
276 | return; | |||
277 | state = state->remove<PreCallSelfFlags>(); | |||
278 | ||||
279 | unsigned NumArgs = CE.getNumArgs(); | |||
280 | for (unsigned i = 0; i < NumArgs; ++i) { | |||
281 | SVal argV = CE.getArgSVal(i); | |||
282 | if (isSelfVar(argV, C)) { | |||
283 | // If the address of 'self' is being passed to the call, assume that the | |||
284 | // 'self' after the call will have the same flags. | |||
285 | // EX: log(&self) | |||
286 | addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C); | |||
287 | return; | |||
288 | } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { | |||
289 | // If 'self' is passed to the call by value, assume that the function | |||
290 | // returns 'self'. So assign the flags, which were set on 'self' to the | |||
291 | // return value. | |||
292 | // EX: self = performMoreInitialization(self) | |||
293 | addSelfFlag(state, CE.getReturnValue(), prevFlags, C); | |||
294 | return; | |||
295 | } | |||
296 | } | |||
297 | ||||
298 | C.addTransition(state); | |||
299 | } | |||
300 | ||||
301 | void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad, | |||
302 | const Stmt *S, | |||
303 | CheckerContext &C) const { | |||
304 | if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( | |||
| ||||
305 | C.getCurrentAnalysisDeclContext()->getDecl()))) | |||
306 | return; | |||
307 | ||||
308 | // Tag the result of a load from 'self' so that we can easily know that the | |||
309 | // value is the object that 'self' points to. | |||
310 | ProgramStateRef state = C.getState(); | |||
311 | if (isSelfVar(location, C)) | |||
312 | addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self, | |||
313 | C); | |||
314 | } | |||
315 | ||||
316 | ||||
317 | void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S, | |||
318 | CheckerContext &C) const { | |||
319 | // Allow assignment of anything to self. Self is a local variable in the | |||
320 | // initializer, so it is legal to assign anything to it, like results of | |||
321 | // static functions/method calls. After self is assigned something we cannot | |||
322 | // reason about, stop enforcing the rules. | |||
323 | // (Only continue checking if the assigned value should be treated as self.) | |||
324 | if ((isSelfVar(loc, C)) && | |||
325 | !hasSelfFlag(val, SelfFlag_InitRes, C) && | |||
326 | !hasSelfFlag(val, SelfFlag_Self, C) && | |||
327 | !isSelfVar(val, C)) { | |||
328 | ||||
329 | // Stop tracking the checker-specific state in the state. | |||
330 | ProgramStateRef State = C.getState(); | |||
331 | State = State->remove<CalledInit>(); | |||
332 | if (SymbolRef sym = loc.getAsSymbol()) | |||
333 | State = State->remove<SelfFlag>(sym); | |||
334 | C.addTransition(State); | |||
335 | } | |||
336 | } | |||
337 | ||||
338 | void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State, | |||
339 | const char *NL, const char *Sep) const { | |||
340 | SelfFlagTy FlagMap = State->get<SelfFlag>(); | |||
341 | bool DidCallInit = State->get<CalledInit>(); | |||
342 | SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get<PreCallSelfFlags>(); | |||
343 | ||||
344 | if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags) | |||
345 | return; | |||
346 | ||||
347 | Out << Sep << NL << *this << " :" << NL; | |||
348 | ||||
349 | if (DidCallInit) | |||
350 | Out << " An init method has been called." << NL; | |||
351 | ||||
352 | if (PreCallFlags != SelfFlag_None) { | |||
353 | if (PreCallFlags & SelfFlag_Self) { | |||
354 | Out << " An argument of the current call came from the 'self' variable." | |||
355 | << NL; | |||
356 | } | |||
357 | if (PreCallFlags & SelfFlag_InitRes) { | |||
358 | Out << " An argument of the current call came from an init method." | |||
359 | << NL; | |||
360 | } | |||
361 | } | |||
362 | ||||
363 | Out << NL; | |||
364 | for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end(); | |||
365 | I != E; ++I) { | |||
366 | Out << I->first << " : "; | |||
367 | ||||
368 | if (I->second == SelfFlag_None) | |||
369 | Out << "none"; | |||
370 | ||||
371 | if (I->second & SelfFlag_Self) | |||
372 | Out << "self variable"; | |||
373 | ||||
374 | if (I->second & SelfFlag_InitRes) { | |||
375 | if (I->second != SelfFlag_InitRes) | |||
376 | Out << " | "; | |||
377 | Out << "result of init method"; | |||
378 | } | |||
379 | ||||
380 | Out << NL; | |||
381 | } | |||
382 | } | |||
383 | ||||
384 | ||||
385 | // FIXME: A callback should disable checkers at the start of functions. | |||
386 | static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { | |||
387 | if (!ND) | |||
388 | return false; | |||
389 | ||||
390 | const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND); | |||
391 | if (!MD) | |||
392 | return false; | |||
393 | if (!isInitializationMethod(MD)) | |||
394 | return false; | |||
395 | ||||
396 | // self = [super init] applies only to NSObject subclasses. | |||
397 | // For instance, NSProxy doesn't implement -init. | |||
398 | ASTContext &Ctx = MD->getASTContext(); | |||
399 | IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); | |||
400 | ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass(); | |||
401 | for ( ; ID ; ID = ID->getSuperClass()) { | |||
402 | IdentifierInfo *II = ID->getIdentifier(); | |||
403 | ||||
404 | if (II == NSObjectII) | |||
405 | break; | |||
406 | } | |||
407 | return ID != nullptr; | |||
408 | } | |||
409 | ||||
410 | /// \brief Returns true if the location is 'self'. | |||
411 | static bool isSelfVar(SVal location, CheckerContext &C) { | |||
412 | AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext(); | |||
413 | if (!analCtx->getSelfDecl()) | |||
414 | return false; | |||
415 | if (!location.getAs<loc::MemRegionVal>()) | |||
416 | return false; | |||
417 | ||||
418 | loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>(); | |||
419 | if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts())) | |||
420 | return (DR->getDecl() == analCtx->getSelfDecl()); | |||
421 | ||||
422 | return false; | |||
423 | } | |||
424 | ||||
425 | static bool isInitializationMethod(const ObjCMethodDecl *MD) { | |||
426 | return MD->getMethodFamily() == OMF_init; | |||
427 | } | |||
428 | ||||
429 | static bool isInitMessage(const ObjCMethodCall &Call) { | |||
430 | return Call.getMethodFamily() == OMF_init; | |||
431 | } | |||
432 | ||||
433 | //===----------------------------------------------------------------------===// | |||
434 | // Registration. | |||
435 | //===----------------------------------------------------------------------===// | |||
436 | ||||
437 | void ento::registerObjCSelfInitChecker(CheckerManager &mgr) { | |||
438 | mgr.registerChecker<ObjCSelfInitChecker>(); | |||
439 | } |