26class ObjCSuperDeallocChecker
27 :
public Checker<check::PostObjCMessage, check::PreObjCMessage,
28 check::PreCall, check::Location> {
33 const BugType DoubleSuperDeallocBugType{
34 this,
"[super dealloc] should not be called more than once",
37 void initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const;
47 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
54 void reportUseAfterDealloc(
SymbolRef Sym, StringRef Desc,
const Stmt *S,
70 SuperDeallocBRVisitor(
SymbolRef ReceiverSymbol)
71 : ReceiverSymbol(ReceiverSymbol), Satisfied(
false) {}
77 void Profile(llvm::FoldingSetNodeID &ID)
const override {
78 ID.Add(ReceiverSymbol);
83void ObjCSuperDeallocChecker::checkPreObjCMessage(
const ObjCMethodCall &M,
88 if (!ReceiverSymbol) {
89 diagnoseCallArguments(M,
C);
93 bool AlreadyCalled = State->contains<CalledSuperDealloc>(ReceiverSymbol);
99 if (isSuperDeallocMessage(M)) {
100 Desc =
"[super dealloc] should not be called multiple times";
105 reportUseAfterDealloc(ReceiverSymbol, Desc, M.
getOriginExpr(),
C);
108void ObjCSuperDeallocChecker::checkPreCall(
const CallEvent &
Call,
110 diagnoseCallArguments(
Call,
C);
113void ObjCSuperDeallocChecker::checkPostObjCMessage(
const ObjCMethodCall &M,
116 if (!isSuperDeallocMessage(M))
121 SymbolRef SelfSymbol = State->getSelfSVal(LC).getAsSymbol();
122 assert(SelfSymbol &&
"No receiver symbol at call to [super dealloc]?");
127 State = State->add<CalledSuperDealloc>(SelfSymbol);
128 C.addTransition(State);
131void ObjCSuperDeallocChecker::checkLocation(
SVal L,
bool IsLoad,
const Stmt *S,
139 if (!State->contains<CalledSuperDealloc>(BaseSym))
148 const MemRegion *PriorSubRegion =
nullptr;
149 while (
const SubRegion *SR = dyn_cast<SubRegion>(R)) {
151 BaseSym = SymR->getSymbol();
154 R = SR->getSuperRegion();
159 StringRef Desc = StringRef();
160 auto *IvarRegion = dyn_cast_or_null<ObjCIvarRegion>(PriorSubRegion);
163 llvm::raw_string_ostream OS(Buf);
165 OS <<
"Use of instance variable '" << *IvarRegion->getDecl() <<
166 "' after 'self' has been deallocated";
170 reportUseAfterDealloc(BaseSym, Desc, S,
C);
176void ObjCSuperDeallocChecker::reportUseAfterDealloc(
SymbolRef Sym,
189 Desc =
"Use of 'self' after it has been deallocated";
192 auto BR = std::make_unique<PathSensitiveBugReport>(DoubleSuperDeallocBugType,
194 BR->addRange(S->getSourceRange());
195 BR->addVisitor(std::make_unique<SuperDeallocBRVisitor>(Sym));
196 C.emitReport(std::move(BR));
201void ObjCSuperDeallocChecker::diagnoseCallArguments(
const CallEvent &CE,
205 for (
unsigned I = 0; I < ArgCount; I++) {
210 if (State->contains<CalledSuperDealloc>(Sym)) {
211 reportUseAfterDealloc(Sym, StringRef(), CE.
getArgExpr(I),
C);
218ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const {
223 IINSObject = &Ctx.
Idents.
get(
"NSObject");
229ObjCSuperDeallocChecker::isSuperDeallocMessage(
const ObjCMethodCall &M)
const {
234 initIdentifierInfoAndSelectors(Ctx);
240SuperDeallocBRVisitor::VisitNode(
const ExplodedNode *Succ,
249 Succ->
getState()->contains<CalledSuperDealloc>(ReceiverSymbol);
256 if (CalledNow && !CalledBefore) {
266 return std::make_shared<PathDiagnosticEventPiece>(
267 L,
"[super dealloc] called here");
281bool ento::shouldRegisterObjCSuperDeallocChecker(
const CheckerManager &mgr) {
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SelectorTable & Selectors
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.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
@ SuperInstance
The receiver is the instance of the superclass object.
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Selector getSelector(unsigned NumArgs, const IdentifierInfo **IIV)
Can create any sort of selector.
Smart pointer class that efficiently represents Objective-C method names.
bool isValid() const
Return true if this is a valid SourceLocation object.
Stmt - This represents one statement.
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
Represents an abstract call to a function or method along a particular path.
const ProgramStateRef & getState() const
The state in which the call is being evaluated.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
ExplodedNode * getFirstPred()
MemRegion - The root abstract class for all memory regions.
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 getReceiverSVal() const
Returns the value of the receiver at the time of this call.
Selector getSelector() const
FullSourceLoc asLocation() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
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.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
SubRegion - A region that subsets another larger region.
SymbolicRegion - A special, "non-concrete" region.
const char *const CoreFoundationObjectiveC
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.