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