ObjCSelfInitChecker.cpp revision b673a41c92aa276f2e37164d0747be1cfb0c402b
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
48using namespace clang;
49using namespace ento;
50
51static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND);
52static bool isInitializationMethod(const ObjCMethodDecl *MD);
53static bool isInitMessage(const ObjCMessage &msg);
54static bool isSelfVar(SVal location, CheckerContext &C);
55
56namespace {
57class 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 > {
64public:
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
75namespace {
76
77class InitSelfBug : public BugType {
78  const std::string desc;
79public:
80  InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"",
81                          "Core Foundation/Objective-C") {}
82};
83
84} // end anonymous namespace
85
86namespace {
87enum 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
97typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
98namespace { struct CalledInit {}; }
99namespace { struct PreCallSelfFlags {}; }
100
101namespace clang {
102namespace 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
123static 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
130static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
131  return getSelfFlags(val, C.getState());
132}
133
134static 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
141static 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.
148static 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
158static 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
179void 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
210void 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
222void 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
250void 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
268void 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
289void 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.
300static 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'.
328static 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
342static bool isInitializationMethod(const ObjCMethodDecl *MD) {
343  return MD->getMethodFamily() == OMF_init;
344}
345
346static bool isInitMessage(const ObjCMessage &msg) {
347  return msg.getMethodFamily() == OMF_init;
348}
349
350//===----------------------------------------------------------------------===//
351// Registration.
352//===----------------------------------------------------------------------===//
353
354void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
355  mgr.registerChecker<ObjCSelfInitChecker>();
356}
357