clang  14.0.0git
ObjCSelfInitChecker.cpp
Go to the documentation of this file.
1 //== ObjCSelfInitChecker.cpp - Checker for 'self' initialization -*- C++ -*--=//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This defines ObjCSelfInitChecker, a builtin check that checks for uses of
10 // 'self' before proper initialization.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 // This checks initialization methods to verify that they assign 'self' to the
15 // result of an initialization call (e.g. [super init], or [self initWith..])
16 // before using 'self' or any instance variable.
17 //
18 // To perform the required checking, values are tagged with flags that indicate
19 // 1) if the object is the one pointed to by 'self', and 2) if the object
20 // is the result of an initializer (e.g. [super init]).
21 //
22 // Uses of an object that is true for 1) but not 2) trigger a diagnostic.
23 // The uses that are currently checked are:
24 // - Using instance variables.
25 // - Returning the object.
26 //
27 // Note that we don't check for an invalid 'self' that is the receiver of an
28 // obj-c message expression to cut down false positives where logging functions
29 // get information from self (like its class) or doing "invalidation" on self
30 // when the initialization fails.
31 //
32 // Because the object that 'self' points to gets invalidated when a call
33 // receives a reference to 'self', the checker keeps track and passes the flags
34 // for 1) and 2) to the new object that 'self' points to after the call.
35 //
36 //===----------------------------------------------------------------------===//
37 
39 #include "clang/AST/ParentMap.h"
46 #include "llvm/Support/raw_ostream.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 ObjCMethodCall &Msg);
54 static bool isSelfVar(SVal location, CheckerContext &C);
55 
56 namespace {
57 class 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 > {
64  mutable std::unique_ptr<BugType> BT;
65 
66  void checkForInvalidSelf(const Expr *E, CheckerContext &C,
67  const char *errorStr) const;
68 
69 public:
70  ObjCSelfInitChecker() {}
71  void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const;
72  void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
73  void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
74  void checkLocation(SVal location, bool isLoad, const Stmt *S,
75  CheckerContext &C) const;
76  void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
77 
78  void checkPreCall(const CallEvent &CE, CheckerContext &C) const;
79  void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
80 
81  void printState(raw_ostream &Out, ProgramStateRef State,
82  const char *NL, const char *Sep) const override;
83 };
84 } // end anonymous namespace
85 
86 namespace {
87 enum SelfFlagEnum {
88  /// No flag set.
89  SelfFlag_None = 0x0,
90  /// Value came from 'self'.
91  SelfFlag_Self = 0x1,
92  /// Value came from the result of an initializer (e.g. [super init]).
93  SelfFlag_InitRes = 0x2
94 };
95 }
96 
97 REGISTER_MAP_WITH_PROGRAMSTATE(SelfFlag, SymbolRef, unsigned)
98 REGISTER_TRAIT_WITH_PROGRAMSTATE(CalledInit, bool)
99 
100 /// A call receiving a reference to 'self' invalidates the object that
101 /// 'self' contains. This keeps the "self flags" assigned to the 'self'
102 /// object before the call so we can assign them to the new object that 'self'
103 /// points to after the call.
104 REGISTER_TRAIT_WITH_PROGRAMSTATE(PreCallSelfFlags, unsigned)
105 
106 static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) {
107  if (SymbolRef sym = val.getAsSymbol())
108  if (const unsigned *attachedFlags = state->get<SelfFlag>(sym))
109  return (SelfFlagEnum)*attachedFlags;
110  return SelfFlag_None;
111 }
112 
113 static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
114  return getSelfFlags(val, C.getState());
115 }
116 
117 static void addSelfFlag(ProgramStateRef state, SVal val,
118  SelfFlagEnum flag, CheckerContext &C) {
119  // We tag the symbol that the SVal wraps.
120  if (SymbolRef sym = val.getAsSymbol()) {
121  state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag);
122  C.addTransition(state);
123  }
124 }
125 
126 static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
127  return getSelfFlags(val, C) & flag;
128 }
129 
130 /// Returns true of the value of the expression is the object that 'self'
131 /// points to and is an object that did not come from the result of calling
132 /// an initializer.
133 static bool isInvalidSelf(const Expr *E, CheckerContext &C) {
134  SVal exprVal = C.getSVal(E);
135  if (!hasSelfFlag(exprVal, SelfFlag_Self, C))
136  return false; // value did not come from 'self'.
137  if (hasSelfFlag(exprVal, SelfFlag_InitRes, C))
138  return false; // 'self' is properly initialized.
139 
140  return true;
141 }
142 
143 void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
144  const char *errorStr) const {
145  if (!E)
146  return;
147 
148  if (!C.getState()->get<CalledInit>())
149  return;
150 
151  if (!isInvalidSelf(E, C))
152  return;
153 
154  // Generate an error node.
155  ExplodedNode *N = C.generateErrorNode();
156  if (!N)
157  return;
158 
159  if (!BT)
160  BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"",
162  C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, errorStr, N));
163 }
164 
165 void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
166  CheckerContext &C) const {
167  // When encountering a message that does initialization (init rule),
168  // tag the return value so that we know later on that if self has this value
169  // then it is properly initialized.
170 
171  // FIXME: A callback should disable checkers at the start of functions.
172  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
173  C.getCurrentAnalysisDeclContext()->getDecl())))
174  return;
175 
176  if (isInitMessage(Msg)) {
177  // Tag the return value as the result of an initializer.
178  ProgramStateRef state = C.getState();
179 
180  // FIXME this really should be context sensitive, where we record
181  // the current stack frame (for IPA). Also, we need to clean this
182  // value out when we return from this method.
183  state = state->set<CalledInit>(true);
184 
185  SVal V = C.getSVal(Msg.getOriginExpr());
186  addSelfFlag(state, V, SelfFlag_InitRes, C);
187  return;
188  }
189 
190  // We don't check for an invalid 'self' in an obj-c message expression to cut
191  // down false positives where logging functions get information from self
192  // (like its class) or doing "invalidation" on self when the initialization
193  // fails.
194 }
195 
196 void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
197  CheckerContext &C) const {
198  // FIXME: A callback should disable checkers at the start of functions.
199  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
200  C.getCurrentAnalysisDeclContext()->getDecl())))
201  return;
202 
203  checkForInvalidSelf(
204  E->getBase(), C,
205  "Instance variable used while 'self' is not set to the result of "
206  "'[(super or self) init...]'");
207 }
208 
209 void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
210  CheckerContext &C) const {
211  // FIXME: A callback should disable checkers at the start of functions.
212  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
213  C.getCurrentAnalysisDeclContext()->getDecl())))
214  return;
215 
216  checkForInvalidSelf(S->getRetValue(), C,
217  "Returning 'self' while it is not set to the result of "
218  "'[(super or self) init...]'");
219 }
220 
221 // When a call receives a reference to 'self', [Pre/Post]Call pass
222 // the SelfFlags from the object 'self' points to before the call to the new
223 // object after the call. This is to avoid invalidation of 'self' by logging
224 // functions.
225 // Another common pattern in classes with multiple initializers is to put the
226 // subclass's common initialization bits into a static function that receives
227 // the value of 'self', e.g:
228 // @code
229 // if (!(self = [super init]))
230 // return nil;
231 // if (!(self = _commonInit(self)))
232 // return nil;
233 // @endcode
234 // Until we can use inter-procedural analysis, in such a call, transfer the
235 // SelfFlags to the result of the call.
236 
237 void ObjCSelfInitChecker::checkPreCall(const CallEvent &CE,
238  CheckerContext &C) const {
239  // FIXME: A callback should disable checkers at the start of functions.
240  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
241  C.getCurrentAnalysisDeclContext()->getDecl())))
242  return;
243 
244  ProgramStateRef state = C.getState();
245  unsigned NumArgs = CE.getNumArgs();
246  // If we passed 'self' as and argument to the call, record it in the state
247  // to be propagated after the call.
248  // Note, we could have just given up, but try to be more optimistic here and
249  // assume that the functions are going to continue initialization or will not
250  // modify self.
251  for (unsigned i = 0; i < NumArgs; ++i) {
252  SVal argV = CE.getArgSVal(i);
253  if (isSelfVar(argV, C)) {
254  unsigned selfFlags = getSelfFlags(state->getSVal(argV.castAs<Loc>()), C);
255  C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
256  return;
257  } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
258  unsigned selfFlags = getSelfFlags(argV, C);
259  C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
260  return;
261  }
262  }
263 }
264 
265 void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
266  CheckerContext &C) const {
267  // FIXME: A callback should disable checkers at the start of functions.
268  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
269  C.getCurrentAnalysisDeclContext()->getDecl())))
270  return;
271 
272  ProgramStateRef state = C.getState();
273  SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
274  if (!prevFlags)
275  return;
276  state = state->remove<PreCallSelfFlags>();
277 
278  unsigned NumArgs = CE.getNumArgs();
279  for (unsigned i = 0; i < NumArgs; ++i) {
280  SVal argV = CE.getArgSVal(i);
281  if (isSelfVar(argV, C)) {
282  // If the address of 'self' is being passed to the call, assume that the
283  // 'self' after the call will have the same flags.
284  // EX: log(&self)
285  addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C);
286  return;
287  } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
288  // If 'self' is passed to the call by value, assume that the function
289  // returns 'self'. So assign the flags, which were set on 'self' to the
290  // return value.
291  // EX: self = performMoreInitialization(self)
292  addSelfFlag(state, CE.getReturnValue(), prevFlags, C);
293  return;
294  }
295  }
296 
297  C.addTransition(state);
298 }
299 
300 void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
301  const Stmt *S,
302  CheckerContext &C) const {
303  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
304  C.getCurrentAnalysisDeclContext()->getDecl())))
305  return;
306 
307  // Tag the result of a load from 'self' so that we can easily know that the
308  // value is the object that 'self' points to.
309  ProgramStateRef state = C.getState();
310  if (isSelfVar(location, C))
311  addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self,
312  C);
313 }
314 
315 
316 void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
317  CheckerContext &C) const {
318  // Allow assignment of anything to self. Self is a local variable in the
319  // initializer, so it is legal to assign anything to it, like results of
320  // static functions/method calls. After self is assigned something we cannot
321  // reason about, stop enforcing the rules.
322  // (Only continue checking if the assigned value should be treated as self.)
323  if ((isSelfVar(loc, C)) &&
324  !hasSelfFlag(val, SelfFlag_InitRes, C) &&
325  !hasSelfFlag(val, SelfFlag_Self, C) &&
326  !isSelfVar(val, C)) {
327 
328  // Stop tracking the checker-specific state in the state.
329  ProgramStateRef State = C.getState();
330  State = State->remove<CalledInit>();
331  if (SymbolRef sym = loc.getAsSymbol())
332  State = State->remove<SelfFlag>(sym);
333  C.addTransition(State);
334  }
335 }
336 
337 void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State,
338  const char *NL, const char *Sep) const {
339  SelfFlagTy FlagMap = State->get<SelfFlag>();
340  bool DidCallInit = State->get<CalledInit>();
341  SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get<PreCallSelfFlags>();
342 
343  if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
344  return;
345 
346  Out << Sep << NL << *this << " :" << NL;
347 
348  if (DidCallInit)
349  Out << " An init method has been called." << NL;
350 
351  if (PreCallFlags != SelfFlag_None) {
352  if (PreCallFlags & SelfFlag_Self) {
353  Out << " An argument of the current call came from the 'self' variable."
354  << NL;
355  }
356  if (PreCallFlags & SelfFlag_InitRes) {
357  Out << " An argument of the current call came from an init method."
358  << NL;
359  }
360  }
361 
362  Out << NL;
363  for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end();
364  I != E; ++I) {
365  Out << I->first << " : ";
366 
367  if (I->second == SelfFlag_None)
368  Out << "none";
369 
370  if (I->second & SelfFlag_Self)
371  Out << "self variable";
372 
373  if (I->second & SelfFlag_InitRes) {
374  if (I->second != SelfFlag_InitRes)
375  Out << " | ";
376  Out << "result of init method";
377  }
378 
379  Out << NL;
380  }
381 }
382 
383 
384 // FIXME: A callback should disable checkers at the start of functions.
385 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
386  if (!ND)
387  return false;
388 
389  const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND);
390  if (!MD)
391  return false;
392  if (!isInitializationMethod(MD))
393  return false;
394 
395  // self = [super init] applies only to NSObject subclasses.
396  // For instance, NSProxy doesn't implement -init.
397  ASTContext &Ctx = MD->getASTContext();
398  IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
400  for ( ; ID ; ID = ID->getSuperClass()) {
401  IdentifierInfo *II = ID->getIdentifier();
402 
403  if (II == NSObjectII)
404  break;
405  }
406  return ID != nullptr;
407 }
408 
409 /// Returns true if the location is 'self'.
410 static bool isSelfVar(SVal location, CheckerContext &C) {
411  AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
412  if (!analCtx->getSelfDecl())
413  return false;
414  if (!location.getAs<loc::MemRegionVal>())
415  return false;
416 
417  loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>();
418  if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
419  return (DR->getDecl() == analCtx->getSelfDecl());
420 
421  return false;
422 }
423 
424 static bool isInitializationMethod(const ObjCMethodDecl *MD) {
425  return MD->getMethodFamily() == OMF_init;
426 }
427 
428 static bool isInitMessage(const ObjCMethodCall &Call) {
429  return Call.getMethodFamily() == OMF_init;
430 }
431 
432 //===----------------------------------------------------------------------===//
433 // Registration.
434 //===----------------------------------------------------------------------===//
435 
436 void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
437  mgr.registerChecker<ObjCSelfInitChecker>();
438 }
439 
440 bool ento::shouldRegisterObjCSelfInitChecker(const CheckerManager &mgr) {
441  return true;
442 }
clang::ObjCInterfaceDecl
Represents an ObjC class declaration.
Definition: DeclObjC.h:1151
getSelfFlags
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)
A call receiving a reference to 'self' invalidates the object that 'self' contains.
Definition: ObjCSelfInitChecker.cpp:106
clang::Decl::getASTContext
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:414
clang::IdentifierTable::get
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Definition: IdentifierTable.h:592
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:249
isInitializationMethod
static bool isInitializationMethod(const ObjCMethodDecl *MD)
Definition: ObjCSelfInitChecker.cpp:424
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::AnalysisDeclContext
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Definition: AnalysisDeclContext.h:72
clang::AnalysisDeclContext::getSelfDecl
const ImplicitParamDecl * getSelfDecl() const
Definition: AnalysisDeclContext.cpp:148
clang::OMF_init
@ OMF_init
Definition: IdentifierTable.h:696
clang::ObjCMethodDecl::getClassInterface
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1164
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
REGISTER_TRAIT_WITH_PROGRAMSTATE
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Definition: ProgramStateTrait.h:33
CallEvent.h
REGISTER_MAP_WITH_PROGRAMSTATE
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Definition: ProgramStateTrait.h:84
V
#define V(N, I)
Definition: ASTContext.h:3121
BuiltinCheckerRegistration.h
hasSelfFlag
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C)
Definition: ObjCSelfInitChecker.cpp:126
CheckerManager.h
clang::ObjCMethodDecl::getMethodFamily
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Definition: DeclObjC.cpp:1006
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:212
isInvalidSelf
static bool isInvalidSelf(const Expr *E, CheckerContext &C)
Returns true of the value of the expression is the object that 'self' points to and is an object that...
Definition: ObjCSelfInitChecker.cpp:133
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
isSelfVar
static bool isSelfVar(SVal location, CheckerContext &C)
Returns true if the location is 'self'.
Definition: ObjCSelfInitChecker.cpp:410
clang::ento::categories::CoreFoundationObjectiveC
const char *const CoreFoundationObjectiveC
Definition: CommonBugCategories.cpp:16
BugType.h
clang::ASTContext::Idents
IdentifierTable & Idents
Definition: ASTContext.h:648
State
LineState State
Definition: UnwrappedLineFormatter.cpp:986
clang::ObjCInterfaceDecl::getSuperClass
ObjCInterfaceDecl * getSuperClass() const
Definition: DeclObjC.cpp:339
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
CheckerContext.h
Checker.h
clang::ObjCMethodDecl
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:139
ParentMap.h
clang::Builtin::ID
ID
Definition: Builtins.h:48
clang
Definition: CalledOnceCheck.h:17
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:69
addSelfFlag
static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C)
Definition: ObjCSelfInitChecker.cpp:117
isInitMessage
static bool isInitMessage(const ObjCMethodCall &Msg)
Definition: ObjCSelfInitChecker.cpp:428
clang::ObjCIvarRefExpr::getBase
const Expr * getBase() const
Definition: ExprObjC.h:580
ProgramStateTrait.h
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::ObjCIvarRefExpr
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:548
shouldRunOnFunctionOrMethod
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)
Definition: ObjCSelfInitChecker.cpp:385
clang::ReturnStmt
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:2760