46#include "llvm/Support/raw_ostream.h"
57class ObjCSelfInitChecker :
public Checker< check::PostObjCMessage,
58 check::PostStmt<ObjCIvarRefExpr>,
59 check::PreStmt<ReturnStmt>,
64 const BugType BT{
this,
"Missing \"self = [(super or self) init...]\"",
67 void checkForInvalidSelf(
const Expr *E, CheckerContext &
C,
68 const char *errorStr)
const;
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,
bool AtDeclInit,
77 CheckerContext &
C)
const;
79 void checkPreCall(
const CallEvent &CE, CheckerContext &
C)
const;
80 void checkPostCall(
const CallEvent &CE, CheckerContext &
C)
const;
83 const char *NL,
const char *Sep)
const override;
94 SelfFlag_InitRes = 0x2
109 if (
const SelfFlagEnum *attachedFlags = state->get<SelfFlag>(sym))
110 return *attachedFlags;
111 return SelfFlag_None;
122 state = state->set<SelfFlag>(sym,
124 C.addTransition(state);
136 SVal exprVal =
C.getSVal(E);
146 const char *errorStr)
const {
150 if (!
C.getState()->get<CalledInit>())
157 ExplodedNode *N =
C.generateErrorNode();
161 C.emitReport(std::make_unique<PathSensitiveBugReport>(BT, errorStr, N));
164void ObjCSelfInitChecker::checkPostObjCMessage(
const ObjCMethodCall &Msg,
165 CheckerContext &
C)
const {
172 C.getCurrentAnalysisDeclContext()->getDecl())))
182 state = state->set<CalledInit>(
true);
195void ObjCSelfInitChecker::checkPostStmt(
const ObjCIvarRefExpr *E,
196 CheckerContext &
C)
const {
199 C.getCurrentAnalysisDeclContext()->getDecl())))
204 "Instance variable used while 'self' is not set to the result of "
205 "'[(super or self) init...]'");
208void ObjCSelfInitChecker::checkPreStmt(
const ReturnStmt *S,
209 CheckerContext &
C)
const {
212 C.getCurrentAnalysisDeclContext()->getDecl())))
216 "Returning 'self' while it is not set to the result of "
217 "'[(super or self) init...]'");
236void ObjCSelfInitChecker::checkPreCall(
const CallEvent &CE,
237 CheckerContext &
C)
const {
240 C.getCurrentAnalysisDeclContext()->getDecl())))
250 for (
unsigned i = 0; i < NumArgs; ++i) {
253 SelfFlagEnum selfFlags =
255 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
259 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
265void ObjCSelfInitChecker::checkPostCall(
const CallEvent &CE,
266 CheckerContext &
C)
const {
269 C.getCurrentAnalysisDeclContext()->getDecl())))
273 SelfFlagEnum prevFlags = state->get<PreCallSelfFlags>();
276 state = state->remove<PreCallSelfFlags>();
279 for (
unsigned i = 0; i < NumArgs; ++i) {
297 C.addTransition(state);
300void ObjCSelfInitChecker::checkLocation(SVal location,
bool isLoad,
302 CheckerContext &
C)
const {
304 C.getCurrentAnalysisDeclContext()->getDecl())))
315void ObjCSelfInitChecker::checkBind(SVal loc, SVal val,
const Stmt *S,
316 bool AtDeclInit, CheckerContext &
C)
const {
329 State = State->remove<CalledInit>();
331 State = State->remove<SelfFlag>(sym);
332 C.addTransition(State);
336void ObjCSelfInitChecker::printState(raw_ostream &Out,
ProgramStateRef State,
337 const char *NL,
const char *Sep)
const {
338 SelfFlagTy FlagMap = State->get<SelfFlag>();
339 bool DidCallInit = State->get<CalledInit>();
340 SelfFlagEnum PreCallFlags = State->get<PreCallSelfFlags>();
342 if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
345 Out << Sep << NL <<
"ObjCSelfInitChecker:" << NL;
348 Out <<
" An init method has been called." << NL;
350 if (PreCallFlags != SelfFlag_None) {
351 if (PreCallFlags & SelfFlag_Self) {
352 Out <<
" An argument of the current call came from the 'self' variable."
355 if (PreCallFlags & SelfFlag_InitRes) {
356 Out <<
" An argument of the current call came from an init method."
362 for (
auto [Sym, Flag] : FlagMap) {
365 if (Flag == SelfFlag_None)
368 if (Flag & SelfFlag_Self)
369 Out <<
"self variable";
371 if (Flag & SelfFlag_InitRes) {
372 if (Flag != SelfFlag_InitRes)
374 Out <<
"result of init method";
398 for ( ; ID ; ID = ID->getSuperClass()) {
401 if (II == NSObjectII)
404 return ID !=
nullptr;
434void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
438bool ento::shouldRegisterObjCSelfInitChecker(
const CheckerManager &mgr) {
static bool isInitMessage(const ObjCMethodCall &Msg)
static bool isSelfVar(SVal location, CheckerContext &C)
Returns true if the location is 'self'.
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)
static bool isInitializationMethod(const ObjCMethodDecl *MD)
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...
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)
A call receiving a reference to 'self' invalidates the object that 'self' contains.
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C)
static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
const ImplicitParamDecl * getSelfDecl() const
ASTContext & getASTContext() const LLVM_READONLY
This represents one expression.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
This represents a decl that may have a name.
Represents an ObjC class declaration.
ObjCInterfaceDecl * getSuperClass() const
const Expr * getBase() const
ObjCMethodDecl - Represents an instance or class method declaration.
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
ObjCInterfaceDecl * getClassInterface()
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SVal getReturnValue() const
Returns the return value of the call.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Represents any expression that calls an Objective-C method.
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * stripCasts(bool StripBaseCasts=true) const
Get the underlining region and strip casts.
const char *const CoreFoundationObjectiveC
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))