aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/CFRefCount.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-02-04 23:49:09 +0000
committerTed Kremenek <kremenek@apple.com>2009-02-04 23:49:09 +0000
commitcf118d41f7930a18dce97416ef7834a62642f587 (patch)
tree6039374169ed1df174e825aac0b026fc6683d561 /lib/Analysis/CFRefCount.cpp
parenta9b66347bec984d1fd0378f85f092e2330344747 (diff)
Overhaul BugReporter interface and implementation. The new interface cleans up
the ownership of BugTypes and BugReports. Now BugReports are owned by BugTypes, and BugTypes are owned by the BugReporter object. The major functionality change in this patch is that reports are not immediately emitted by a call to BugReporter::EmitWarning (now called EmitReport), but instead of queued up in report "equivalence classes". When BugReporter::FlushReports() is called, it emits one diagnostic per report equivalence class. This provides a nice cleanup with the caching of reports as well as enables the BugReporter engine to select the "best" path for reporting a path-sensitive bug based on all the locations in the ExplodedGraph that the same bug could occur. Along with this patch, Leaks are now coalesced into a common equivalence class by their allocation site, and the "summary" diagnostic for leaks now reports the allocation site as the location of the bug (this may later be augmented to also provide an example location where the leak occurs). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63796 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFRefCount.cpp')
-rw-r--r--lib/Analysis/CFRefCount.cpp187
1 files changed, 91 insertions, 96 deletions
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index ab9d409dd2..e42fa8614c 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -1333,7 +1333,7 @@ public:
delete I->second;
}
- virtual void RegisterChecks(GRExprEngine& Eng);
+ void RegisterChecks(BugReporter &BR);
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {
Printers.push_back(new BindingsPrinter());
@@ -2154,91 +2154,73 @@ namespace {
// Bug Descriptions. //
//===-------------===//
- class VISIBILITY_HIDDEN CFRefBug : public BugTypeCacheLocation {
+ class VISIBILITY_HIDDEN CFRefBug : public BugType {
protected:
CFRefCount& TF;
-
+
+ CFRefBug(CFRefCount* tf, const char* name)
+ : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
public:
- CFRefBug(CFRefCount& tf) : TF(tf) {}
CFRefCount& getTF() { return TF; }
const CFRefCount& getTF() const { return TF; }
+ // FIXME: Eventually remove.
+ virtual const char* getDescription() const = 0;
+
virtual bool isLeak() const { return false; }
-
- const char* getCategory() const {
- return "Memory (Core Foundation/Objective-C)";
- }
};
class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
public:
- UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
+ UseAfterRelease(CFRefCount* tf)
+ : CFRefBug(tf, "use-after-release") {}
- virtual const char* getName() const {
- return "use-after-release";
- }
- virtual const char* getDescription() const {
+ const char* getDescription() const {
return "Reference-counted object is used after it is released.";
}
- virtual void EmitWarnings(BugReporter& BR);
+ virtual void FlushReports(BugReporter& BR);
};
class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
public:
- BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
-
- virtual const char* getName() const {
- return "bad release";
- }
- virtual const char* getDescription() const {
+ BadRelease(CFRefCount* tf) : CFRefBug(tf, "bad release") {}
+
+ const char* getDescription() const {
return "Incorrect decrement of the reference count of a "
"CoreFoundation object: "
"The object is not owned at this point by the caller.";
}
- virtual void EmitWarnings(BugReporter& BR);
+ void FlushReports(BugReporter& BR);
};
class VISIBILITY_HIDDEN Leak : public CFRefBug {
- bool isReturn;
+ const bool isReturn;
+ protected:
+ Leak(CFRefCount* tf, const char* name, bool isRet)
+ : CFRefBug(tf, name), isReturn(isRet) {}
public:
- Leak(CFRefCount& tf) : CFRefBug(tf) {}
- void setIsReturn(bool x) { isReturn = x; }
-
- virtual const char* getName() const {
-
- if (!isReturn) {
- if (getTF().isGCEnabled())
- return "leak (GC)";
-
- if (getTF().getLangOptions().getGCMode() == LangOptions::HybridGC)
- return "leak (hybrid MM, non-GC)";
-
- assert (getTF().getLangOptions().getGCMode() == LangOptions::NonGC);
- return "leak";
- }
- else {
- if (getTF().isGCEnabled())
- return "[naming convention] leak of returned object (GC)";
-
- if (getTF().getLangOptions().getGCMode() == LangOptions::HybridGC)
- return "[naming convention] leak of returned object (hybrid MM, "
- "non-GC)";
-
- assert (getTF().getLangOptions().getGCMode() == LangOptions::NonGC);
- return "[naming convention] leak of returned object";
- }
- }
+ // FIXME: Remove once reports have better descriptions.
+ const char* getDescription() const { return "leak"; }
- virtual void EmitWarnings(BugReporter& BR);
- virtual void GetErrorNodes(std::vector<ExplodedNode<GRState>*>& Nodes);
- virtual bool isLeak() const { return true; }
- virtual bool isCached(BugReport& R);
+ void FlushReports(BugReporter &BR);
+ };
+
+ class VISIBILITY_HIDDEN LeakAtReturn : public Leak {
+ public:
+ LeakAtReturn(CFRefCount* tf, const char* name)
+ : Leak(tf, name, true) {}
};
+ class VISIBILITY_HIDDEN LeakWithinFunction : public Leak {
+ public:
+ LeakWithinFunction(CFRefCount* tf, const char* name)
+ : Leak(tf, name, false) {}
+ };
+
//===---------===//
// Bug Reports. //
//===---------===//
@@ -2247,7 +2229,7 @@ namespace {
SymbolRef Sym;
public:
CFRefReport(CFRefBug& D, ExplodedNode<GRState> *n, SymbolRef sym)
- : RangedBugReport(D, n), Sym(sym) {}
+ : RangedBugReport(D, D.getDescription(), n), Sym(sym) {}
virtual ~CFRefReport() {}
@@ -2278,17 +2260,49 @@ namespace {
const ExplodedNode<GRState>* PrevN,
const ExplodedGraph<GRState>& G,
BugReporter& BR);
+
};
-
+ class VISIBILITY_HIDDEN CFRefLeakReport : public CFRefReport {
+ public:
+ CFRefLeakReport(CFRefBug& D, ExplodedNode<GRState> *n, SymbolRef sym)
+ : CFRefReport(D, n, sym) {}
+
+ SourceLocation getLocation() const;
+ };
} // end anonymous namespace
-void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
- Eng.Register(new UseAfterRelease(*this));
- Eng.Register(new BadRelease(*this));
- Eng.Register(new Leak(*this));
-}
+void CFRefCount::RegisterChecks(BugReporter& BR) {
+ BR.Register(new UseAfterRelease(this));
+ BR.Register(new BadRelease(this));
+
+ // First register "return" leaks.
+ const char* name = 0;
+
+ if (isGCEnabled())
+ name = "[naming convention] leak of returned object (GC)";
+ else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+ name = "[naming convention] leak of returned object (hybrid MM, "
+ "non-GC)";
+ else {
+ assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+ name = "[naming convention] leak of returned object";
+ }
+
+ BR.Register(new LeakAtReturn(this, name));
+ // Second, register leaks within a function/method.
+ if (isGCEnabled())
+ name = "leak (GC)";
+ else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+ name = "leak (hybrid MM, non-GC)";
+ else {
+ assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+ name = "leak";
+ }
+
+ BR.Register(new LeakWithinFunction(this, name));
+}
static const char* Msgs[] = {
"Code is compiled in garbage collection only mode" // GC only
@@ -2621,30 +2635,25 @@ CFRefReport::getEndPath(BugReporter& br, const ExplodedNode<GRState>* EndN) {
return new PathDiagnosticPiece(L, os.str(), Hint);
}
-void UseAfterRelease::EmitWarnings(BugReporter& BR) {
-
+void UseAfterRelease::FlushReports(BugReporter& BR) {
for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
- E = TF.use_after_end(); I != E; ++I) {
-
- CFRefReport report(*this, I->first, I->second.second);
- report.addRange(I->second.first->getSourceRange());
- BR.EmitWarning(report);
+ E = TF.use_after_end(); I != E; ++I) {
+ CFRefReport *report = new CFRefReport(*this, I->first, I->second.second);
+ report->addRange(I->second.first->getSourceRange());
+ BR.EmitReport(report);
}
}
-void BadRelease::EmitWarnings(BugReporter& BR) {
-
+void BadRelease::FlushReports(BugReporter& BR) {
for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
E = TF.bad_release_end(); I != E; ++I) {
-
- CFRefReport report(*this, I->first, I->second.second);
- report.addRange(I->second.first->getSourceRange());
- BR.EmitWarning(report);
+ CFRefReport *report = new CFRefReport(*this, I->first, I->second.second);
+ report->addRange(I->second.first->getSourceRange());
+ BR.EmitReport(report);
}
}
-void Leak::EmitWarnings(BugReporter& BR) {
-
+void Leak::FlushReports(BugReporter& BR) {
for (CFRefCount::leaks_iterator I = TF.leaks_begin(),
E = TF.leaks_end(); I != E; ++I) {
@@ -2652,34 +2661,20 @@ void Leak::EmitWarnings(BugReporter& BR) {
unsigned n = SymV.size();
for (unsigned i = 0; i < n; ++i) {
- setIsReturn(SymV[i].second);
- CFRefReport report(*this, I->first, SymV[i].first);
- BR.EmitWarning(report);
+ if (isReturn != SymV[i].second) continue;
+ CFRefReport* report = new CFRefLeakReport(*this, I->first, SymV[i].first);
+ BR.EmitReport(report);
}
}
}
-void Leak::GetErrorNodes(std::vector<ExplodedNode<GRState>*>& Nodes) {
- for (CFRefCount::leaks_iterator I=TF.leaks_begin(), E=TF.leaks_end();
- I!=E; ++I)
- Nodes.push_back(I->first);
-}
-
-bool Leak::isCached(BugReport& R) {
-
+SourceLocation CFRefLeakReport::getLocation() const {
// Most bug reports are cached at the location where they occured.
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
-
- SymbolRef Sym = static_cast<CFRefReport&>(R).getSymbol();
-
- const ExplodedNode<GRState>* AllocNode =
- GetAllocationSite(0, R.getEndNode(), Sym).first;
-
- if (!AllocNode)
- return false;
-
- return BugTypeCacheLocation::isCached(AllocNode->getLocation());
+ ProgramPoint P =
+ GetAllocationSite(0, getEndNode(), getSymbol()).first->getLocation();
+ return cast<PostStmt>(P).getStmt()->getLocStart();
}
//===----------------------------------------------------------------------===//