23 using namespace clang;
27 class ObjCSuperDeallocChecker
28 :
public Checker<check::PostObjCMessage, check::PreObjCMessage,
29 check::PreCall, check::Location> {
34 std::unique_ptr<BugType> DoubleSuperDeallocBugType;
36 void initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const;
41 ObjCSuperDeallocChecker();
47 void checkLocation(
SVal l,
bool isLoad,
const Stmt *
S,
54 void reportUseAfterDealloc(
SymbolRef Sym, StringRef Desc,
const Stmt *
S,
65 class SuperDeallocBRVisitor final
72 SuperDeallocBRVisitor(
SymbolRef ReceiverSymbol)
73 : ReceiverSymbol(ReceiverSymbol),
81 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
82 ID.Add(ReceiverSymbol);
87 void ObjCSuperDeallocChecker::checkPreObjCMessage(
const ObjCMethodCall &M,
92 if (!ReceiverSymbol) {
93 diagnoseCallArguments(M, C);
97 bool AlreadyCalled = State->contains<CalledSuperDealloc>(ReceiverSymbol);
103 if (isSuperDeallocMessage(M)) {
104 Desc =
"[super dealloc] should not be called multiple times";
109 reportUseAfterDealloc(ReceiverSymbol, Desc, M.
getOriginExpr(), C);
114 void ObjCSuperDeallocChecker::checkPreCall(
const CallEvent &Call,
116 diagnoseCallArguments(Call, C);
119 void ObjCSuperDeallocChecker::checkPostObjCMessage(
const ObjCMethodCall &M,
122 if (!isSuperDeallocMessage(M))
127 assert(ReceiverSymbol &&
"No receiver symbol at call to [super dealloc]?");
132 State = State->add<CalledSuperDealloc>(ReceiverSymbol);
136 void ObjCSuperDeallocChecker::checkLocation(
SVal L,
bool IsLoad,
const Stmt *
S,
144 if (!State->contains<CalledSuperDealloc>(BaseSym))
153 const MemRegion *PriorSubRegion =
nullptr;
154 while (
const SubRegion *SR = dyn_cast<SubRegion>(R)) {
156 BaseSym = SymR->getSymbol();
159 R = SR->getSuperRegion();
164 StringRef Desc = StringRef();
165 auto *IvarRegion = dyn_cast_or_null<ObjCIvarRegion>(PriorSubRegion);
168 llvm::raw_string_ostream OS(Buf);
170 OS <<
"Use of instance variable '" << *IvarRegion->getDecl() <<
171 "' after 'self' has been deallocated";
175 reportUseAfterDealloc(BaseSym, Desc, S, C);
181 void ObjCSuperDeallocChecker::reportUseAfterDealloc(
SymbolRef Sym,
194 Desc =
"use of 'self' after it has been deallocated";
197 std::unique_ptr<BugReport> BR(
198 new BugReport(*DoubleSuperDeallocBugType, Desc, ErrNode));
199 BR->addRange(S->getSourceRange());
200 BR->addVisitor(llvm::make_unique<SuperDeallocBRVisitor>(Sym));
206 void ObjCSuperDeallocChecker::diagnoseCallArguments(
const CallEvent &CE,
210 for (
unsigned I = 0;
I < ArgCount;
I++) {
215 if (State->contains<CalledSuperDealloc>(Sym)) {
216 reportUseAfterDealloc(Sym, StringRef(), CE.
getArgExpr(
I), C);
222 ObjCSuperDeallocChecker::ObjCSuperDeallocChecker()
223 : IIdealloc(nullptr), IINSObject(nullptr) {
225 DoubleSuperDeallocBugType.reset(
226 new BugType(
this,
"[super dealloc] should not be called more than once",
231 ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const {
236 IINSObject = &Ctx.
Idents.
get(
"NSObject");
242 ObjCSuperDeallocChecker::isSuperDeallocMessage(
const ObjCMethodCall &M)
const {
246 ASTContext &Ctx = M.getState()->getStateManager().getContext();
247 initIdentifierInfoAndSelectors(Ctx);
262 Succ->
getState()->contains<CalledSuperDealloc>(ReceiverSymbol);
264 Pred->
getState()->contains<CalledSuperDealloc>(ReceiverSymbol);
268 if (CalledNow && !CalledBefore) {
279 L,
"[super dealloc] called here");
291 if (LangOpts.getGC() == LangOptions::GCOnly || LangOpts.ObjCAutoRefCount)
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
const char *const CoreFoundationObjectiveC
Smart pointer class that efficiently represents Objective-C method names.
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
SVal getSelfSVal() const
Return the value of 'self' if available.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
FullSourceLoc asLocation() const
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
This class provides a convenience implementation for clone() using the Curiously-Recurring Template P...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents any expression that calls an Objective-C method.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
detail::InMemoryDirectory::const_iterator I
SymbolicRegion - A special, "non-concrete" region.
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
const ProgramStateRef & getState() const
const ProgramStateRef & getState() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
SelectorTable & Selectors
CHECKER * registerChecker()
Used to register checkers.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
bool isValid() const
Return true if this is a valid SourceLocation object.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Selector getSelector() const
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx)
const LangOptions & getLangOpts() const
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
const MemRegion * getAsRegion() const
Represents an abstract call to a function or method along a particular path.
SubRegion - A region that subsets another larger region.
Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV)
Can create any sort of selector.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
This class provides an interface through which checkers can create individual bug reports...
virtual const ObjCMessageExpr * getOriginExpr() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
SourceManager & getSourceManager()