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,
70 SuperDeallocBRVisitor(
SymbolRef ReceiverSymbol)
71 : ReceiverSymbol(ReceiverSymbol),
74 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *Succ,
79 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
80 ID.Add(ReceiverSymbol);
85 void ObjCSuperDeallocChecker::checkPreObjCMessage(
const ObjCMethodCall &M,
90 if (!ReceiverSymbol) {
91 diagnoseCallArguments(M, C);
95 bool AlreadyCalled = State->contains<CalledSuperDealloc>(ReceiverSymbol);
101 if (isSuperDeallocMessage(M)) {
102 Desc =
"[super dealloc] should not be called multiple times";
107 reportUseAfterDealloc(ReceiverSymbol, Desc, M.
getOriginExpr(), C);
110 void ObjCSuperDeallocChecker::checkPreCall(
const CallEvent &Call,
112 diagnoseCallArguments(Call, C);
115 void ObjCSuperDeallocChecker::checkPostObjCMessage(
const ObjCMethodCall &M,
118 if (!isSuperDeallocMessage(M))
123 assert(ReceiverSymbol &&
"No receiver symbol at call to [super dealloc]?");
128 State = State->add<CalledSuperDealloc>(ReceiverSymbol);
132 void ObjCSuperDeallocChecker::checkLocation(
SVal L,
bool IsLoad,
const Stmt *S,
140 if (!State->contains<CalledSuperDealloc>(BaseSym))
149 const MemRegion *PriorSubRegion =
nullptr;
150 while (
const SubRegion *SR = dyn_cast<SubRegion>(R)) {
152 BaseSym = SymR->getSymbol();
155 R = SR->getSuperRegion();
160 StringRef Desc = StringRef();
161 auto *IvarRegion = dyn_cast_or_null<ObjCIvarRegion>(PriorSubRegion);
164 llvm::raw_string_ostream OS(Buf);
166 OS <<
"Use of instance variable '" << *IvarRegion->getDecl() <<
167 "' after 'self' has been deallocated";
171 reportUseAfterDealloc(BaseSym, Desc, S, C);
177 void ObjCSuperDeallocChecker::reportUseAfterDealloc(
SymbolRef Sym,
190 Desc =
"Use of 'self' after it has been deallocated";
193 std::unique_ptr<BugReport> BR(
194 new BugReport(*DoubleSuperDeallocBugType, Desc, ErrNode));
196 BR->addVisitor(llvm::make_unique<SuperDeallocBRVisitor>(Sym));
202 void ObjCSuperDeallocChecker::diagnoseCallArguments(
const CallEvent &CE,
206 for (
unsigned I = 0; I < ArgCount; I++) {
211 if (State->contains<CalledSuperDealloc>(Sym)) {
212 reportUseAfterDealloc(Sym, StringRef(), CE.
getArgExpr(I), C);
218 ObjCSuperDeallocChecker::ObjCSuperDeallocChecker()
219 : IIdealloc(nullptr), IINSObject(nullptr) {
221 DoubleSuperDeallocBugType.reset(
222 new BugType(
this,
"[super dealloc] should not be called more than once",
227 ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors(
ASTContext &Ctx)
const {
232 IINSObject = &Ctx.
Idents.
get(
"NSObject");
238 ObjCSuperDeallocChecker::isSuperDeallocMessage(
const ObjCMethodCall &M)
const {
242 ASTContext &Ctx = M.getState()->getStateManager().getContext();
243 initIdentifierInfoAndSelectors(Ctx);
248 std::shared_ptr<PathDiagnosticPiece>
249 SuperDeallocBRVisitor::VisitNode(
const ExplodedNode *Succ,
258 Succ->
getState()->contains<CalledSuperDealloc>(ReceiverSymbol);
260 Pred->
getState()->contains<CalledSuperDealloc>(ReceiverSymbol);
264 if (CalledNow && !CalledBefore) {
274 return std::make_shared<PathDiagnosticEventPiece>(
275 L,
"[super dealloc] called here");
287 if (LangOpts.getGC() == LangOptions::GCOnly || LangOpts.ObjCAutoRefCount)
SVal getSelfSVal() const
Return the value of 'self' if available.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this 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.
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
Stmt - This represents one statement.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
const ProgramStateRef & getState() const
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
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 ...
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
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.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
SymbolicRegion - A special, "non-concrete" region.
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
CHECKER * registerChecker(AT... Args)
Used to register checkers.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
SelectorTable & Selectors
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
const MemRegion * getAsRegion() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
FullSourceLoc asLocation() const
virtual const ObjCMessageExpr * getOriginExpr() const
Selector getSelector() const
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
Represents an abstract call to a function or method along a particular path.
SubRegion - A region that subsets another larger region.
const ProgramStateRef & getState() const
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).
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
This class provides an interface through which checkers can create individual bug reports...
const LangOptions & getLangOpts() const
SourceManager & getSourceManager()