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