xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp (revision e98d63a823f02aa920e9cd4889c303f8e2ad7592)
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/StaticAnalyzer/Core/Checker.h"
41 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
42 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
43 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
44 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
45 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46 #include "clang/AST/ParentMap.h"
47 
48 using namespace clang;
49 using namespace ento;
50 
51 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND);
52 static bool isInitializationMethod(const ObjCMethodDecl *MD);
53 static bool isInitMessage(const ObjCMessage &msg);
54 static bool isSelfVar(SVal location, CheckerContext &C);
55 
56 namespace {
57 class ObjCSelfInitChecker : public Checker<
58                                              check::PostObjCMessage,
59                                              check::PostStmt<ObjCIvarRefExpr>,
60                                              check::PreStmt<ReturnStmt>,
61                                              check::PreStmt<CallExpr>,
62                                              check::PostStmt<CallExpr>,
63                                              check::Location > {
64 public:
65   void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
66   void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
67   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
68   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
69   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
70   void checkLocation(SVal location, bool isLoad, const Stmt *S,
71                      CheckerContext &C) const;
72 };
73 } // end anonymous namespace
74 
75 namespace {
76 
77 class InitSelfBug : public BugType {
78   const std::string desc;
79 public:
80   InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"",
81                           "Core Foundation/Objective-C") {}
82 };
83 
84 } // end anonymous namespace
85 
86 namespace {
87 enum SelfFlagEnum {
88   /// \brief No flag set.
89   SelfFlag_None = 0x0,
90   /// \brief Value came from 'self'.
91   SelfFlag_Self    = 0x1,
92   /// \brief Value came from the result of an initializer (e.g. [super init]).
93   SelfFlag_InitRes = 0x2
94 };
95 }
96 
97 typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
98 namespace { struct CalledInit {}; }
99 namespace { struct PreCallSelfFlags {}; }
100 
101 namespace clang {
102 namespace ento {
103   template<>
104   struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> {
105     static void *GDMIndex() { static int index = 0; return &index; }
106   };
107   template <>
108   struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> {
109     static void *GDMIndex() { static int index = 0; return &index; }
110   };
111 
112   /// \brief A call receiving a reference to 'self' invalidates the object that
113   /// 'self' contains. This keeps the "self flags" assigned to the 'self'
114   /// object before the call so we can assign them to the new object that 'self'
115   /// points to after the call.
116   template <>
117   struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> {
118     static void *GDMIndex() { static int index = 0; return &index; }
119   };
120 }
121 }
122 
123 static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) {
124   if (SymbolRef sym = val.getAsSymbol())
125     if (const unsigned *attachedFlags = state->get<SelfFlag>(sym))
126       return (SelfFlagEnum)*attachedFlags;
127   return SelfFlag_None;
128 }
129 
130 static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
131   return getSelfFlags(val, C.getState());
132 }
133 
134 static void addSelfFlag(ProgramStateRef state, SVal val,
135                         SelfFlagEnum flag, CheckerContext &C) {
136   // We tag the symbol that the SVal wraps.
137   if (SymbolRef sym = val.getAsSymbol())
138     C.addTransition(state->set<SelfFlag>(sym, getSelfFlags(val, C) | flag));
139 }
140 
141 static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
142   return getSelfFlags(val, C) & flag;
143 }
144 
145 /// \brief Returns true of the value of the expression is the object that 'self'
146 /// points to and is an object that did not come from the result of calling
147 /// an initializer.
148 static bool isInvalidSelf(const Expr *E, CheckerContext &C) {
149   SVal exprVal = C.getState()->getSVal(E, C.getLocationContext());
150   if (!hasSelfFlag(exprVal, SelfFlag_Self, C))
151     return false; // value did not come from 'self'.
152   if (hasSelfFlag(exprVal, SelfFlag_InitRes, C))
153     return false; // 'self' is properly initialized.
154 
155   return true;
156 }
157 
158 static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
159                                 const char *errorStr) {
160   if (!E)
161     return;
162 
163   if (!C.getState()->get<CalledInit>())
164     return;
165 
166   if (!isInvalidSelf(E, C))
167     return;
168 
169   // Generate an error node.
170   ExplodedNode *N = C.generateSink();
171   if (!N)
172     return;
173 
174   BugReport *report =
175     new BugReport(*new InitSelfBug(), errorStr, N);
176   C.EmitReport(report);
177 }
178 
179 void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
180                                                CheckerContext &C) const {
181   // When encountering a message that does initialization (init rule),
182   // tag the return value so that we know later on that if self has this value
183   // then it is properly initialized.
184 
185   // FIXME: A callback should disable checkers at the start of functions.
186   if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
187                                 C.getCurrentAnalysisDeclContext()->getDecl())))
188     return;
189 
190   if (isInitMessage(msg)) {
191     // Tag the return value as the result of an initializer.
192     ProgramStateRef state = C.getState();
193 
194     // FIXME this really should be context sensitive, where we record
195     // the current stack frame (for IPA).  Also, we need to clean this
196     // value out when we return from this method.
197     state = state->set<CalledInit>(true);
198 
199     SVal V = state->getSVal(msg.getMessageExpr(), C.getLocationContext());
200     addSelfFlag(state, V, SelfFlag_InitRes, C);
201     return;
202   }
203 
204   // We don't check for an invalid 'self' in an obj-c message expression to cut
205   // down false positives where logging functions get information from self
206   // (like its class) or doing "invalidation" on self when the initialization
207   // fails.
208 }
209 
210 void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
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(E->getBase(), C,
218     "Instance variable used while 'self' is not set to the result of "
219                                                  "'[(super or self) init...]'");
220 }
221 
222 void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
223                                        CheckerContext &C) const {
224   // FIXME: A callback should disable checkers at the start of functions.
225   if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
226                                  C.getCurrentAnalysisDeclContext()->getDecl())))
227     return;
228 
229   checkForInvalidSelf(S->getRetValue(), C,
230     "Returning 'self' while it is not set to the result of "
231                                                  "'[(super or self) init...]'");
232 }
233 
234 // When a call receives a reference to 'self', [Pre/Post]VisitGenericCall pass
235 // the SelfFlags from the object 'self' point to before the call, to the new
236 // object after the call. This is to avoid invalidation of 'self' by logging
237 // functions.
238 // Another common pattern in classes with multiple initializers is to put the
239 // subclass's common initialization bits into a static function that receives
240 // the value of 'self', e.g:
241 // @code
242 //   if (!(self = [super init]))
243 //     return nil;
244 //   if (!(self = _commonInit(self)))
245 //     return nil;
246 // @endcode
247 // Until we can use inter-procedural analysis, in such a call, transfer the
248 // SelfFlags to the result of the call.
249 
250 void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
251                                        CheckerContext &C) const {
252   ProgramStateRef state = C.getState();
253   for (CallExpr::const_arg_iterator
254          I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
255     SVal argV = state->getSVal(*I, C.getLocationContext());
256     if (isSelfVar(argV, C)) {
257       unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
258       C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
259       return;
260     } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
261       unsigned selfFlags = getSelfFlags(argV, C);
262       C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
263       return;
264     }
265   }
266 }
267 
268 void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
269                                         CheckerContext &C) const {
270   ProgramStateRef state = C.getState();
271   const LocationContext *LCtx = C.getLocationContext();
272   for (CallExpr::const_arg_iterator
273          I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
274     SVal argV = state->getSVal(*I, LCtx);
275     if (isSelfVar(argV, C)) {
276       SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
277       state = state->remove<PreCallSelfFlags>();
278       addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
279       return;
280     } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
281       SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
282       state = state->remove<PreCallSelfFlags>();
283       addSelfFlag(state, state->getSVal(CE, LCtx), prevFlags, C);
284       return;
285     }
286   }
287 }
288 
289 void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
290                                         const Stmt *S,
291                                         CheckerContext &C) const {
292   // Tag the result of a load from 'self' so that we can easily know that the
293   // value is the object that 'self' points to.
294   ProgramStateRef state = C.getState();
295   if (isSelfVar(location, C))
296     addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C);
297 }
298 
299 // FIXME: A callback should disable checkers at the start of functions.
300 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
301   if (!ND)
302     return false;
303 
304   const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND);
305   if (!MD)
306     return false;
307   if (!isInitializationMethod(MD))
308     return false;
309 
310   // self = [super init] applies only to NSObject subclasses.
311   // For instance, NSProxy doesn't implement -init.
312   ASTContext &Ctx = MD->getASTContext();
313   IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
314   ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass();
315   for ( ; ID ; ID = ID->getSuperClass()) {
316     IdentifierInfo *II = ID->getIdentifier();
317 
318     if (II == NSObjectII)
319       break;
320   }
321   if (!ID)
322     return false;
323 
324   return true;
325 }
326 
327 /// \brief Returns true if the location is 'self'.
328 static bool isSelfVar(SVal location, CheckerContext &C) {
329   AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
330   if (!analCtx->getSelfDecl())
331     return false;
332   if (!isa<loc::MemRegionVal>(location))
333     return false;
334 
335   loc::MemRegionVal MRV = cast<loc::MemRegionVal>(location);
336   if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.getRegion()))
337     return (DR->getDecl() == analCtx->getSelfDecl());
338 
339   return false;
340 }
341 
342 static bool isInitializationMethod(const ObjCMethodDecl *MD) {
343   return MD->getMethodFamily() == OMF_init;
344 }
345 
346 static bool isInitMessage(const ObjCMessage &msg) {
347   return msg.getMethodFamily() == OMF_init;
348 }
349 
350 //===----------------------------------------------------------------------===//
351 // Registration.
352 //===----------------------------------------------------------------------===//
353 
354 void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
355   mgr.registerChecker<ObjCSelfInitChecker>();
356 }
357