26class ObjCSuperDeallocChecker
27 :
public Checker<check::PostObjCMessage, check::PreObjCMessage,
28 check::PreCall, check::Location> {
33 std::unique_ptr<BugType> DoubleSuperDeallocBugType;
35 void initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const;
40 ObjCSuperDeallocChecker();
46 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
53 void reportUseAfterDealloc(
SymbolRef Sym, StringRef Desc,
const Stmt *S,
69 SuperDeallocBRVisitor(
SymbolRef ReceiverSymbol)
70 : ReceiverSymbol(ReceiverSymbol), Satisfied(
false) {}
76 void Profile(llvm::FoldingSetNodeID &ID)
const override {
77 ID.Add(ReceiverSymbol);
82void ObjCSuperDeallocChecker::checkPreObjCMessage(
const ObjCMethodCall &M,
87 if (!ReceiverSymbol) {
88 diagnoseCallArguments(M,
C);
92 bool AlreadyCalled = State->contains<CalledSuperDealloc>(ReceiverSymbol);
98 if (isSuperDeallocMessage(M)) {
99 Desc =
"[super dealloc] should not be called multiple times";
104 reportUseAfterDealloc(ReceiverSymbol, Desc, M.
getOriginExpr(),
C);
107void ObjCSuperDeallocChecker::checkPreCall(
const CallEvent &
Call,
109 diagnoseCallArguments(
Call,
C);
112void ObjCSuperDeallocChecker::checkPostObjCMessage(
const ObjCMethodCall &M,
115 if (!isSuperDeallocMessage(M))
120 SymbolRef SelfSymbol = State->getSelfSVal(LC).getAsSymbol();
121 assert(SelfSymbol &&
"No receiver symbol at call to [super dealloc]?");
126 State = State->add<CalledSuperDealloc>(SelfSymbol);
127 C.addTransition(State);
130void ObjCSuperDeallocChecker::checkLocation(
SVal L,
bool IsLoad,
const Stmt *S,
138 if (!State->contains<CalledSuperDealloc>(BaseSym))
147 const MemRegion *PriorSubRegion =
nullptr;
148 while (
const SubRegion *SR = dyn_cast<SubRegion>(R)) {
150 BaseSym = SymR->getSymbol();
153 R = SR->getSuperRegion();
158 StringRef Desc = StringRef();
159 auto *IvarRegion = dyn_cast_or_null<ObjCIvarRegion>(PriorSubRegion);
162 llvm::raw_string_ostream OS(Buf);
164 OS <<
"Use of instance variable '" << *IvarRegion->getDecl() <<
165 "' after 'self' has been deallocated";
169 reportUseAfterDealloc(BaseSym, Desc, S,
C);
175void ObjCSuperDeallocChecker::reportUseAfterDealloc(
SymbolRef Sym,
188 Desc =
"Use of 'self' after it has been deallocated";
191 auto BR = std::make_unique<PathSensitiveBugReport>(*DoubleSuperDeallocBugType,
193 BR->addRange(S->getSourceRange());
194 BR->addVisitor(std::make_unique<SuperDeallocBRVisitor>(Sym));
195 C.emitReport(std::move(BR));
200void ObjCSuperDeallocChecker::diagnoseCallArguments(
const CallEvent &CE,
204 for (
unsigned I = 0; I < ArgCount; I++) {
209 if (State->contains<CalledSuperDealloc>(Sym)) {
210 reportUseAfterDealloc(Sym, StringRef(), CE.
getArgExpr(I),
C);
216ObjCSuperDeallocChecker::ObjCSuperDeallocChecker()
217 : IIdealloc(nullptr), IINSObject(nullptr) {
219 DoubleSuperDeallocBugType.reset(
220 new BugType(
this,
"[super dealloc] should not be called more than once",
225ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const {
230 IINSObject = &Ctx.
Idents.
get(
"NSObject");
236ObjCSuperDeallocChecker::isSuperDeallocMessage(
const ObjCMethodCall &M)
const {
241 initIdentifierInfoAndSelectors(Ctx);
247SuperDeallocBRVisitor::VisitNode(
const ExplodedNode *Succ,
256 Succ->
getState()->contains<CalledSuperDealloc>(ReceiverSymbol);
263 if (CalledNow && !CalledBefore) {
273 return std::make_shared<PathDiagnosticEventPiece>(
274 L,
"[super dealloc] called here");
288bool 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, 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