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