Cache leaks by the allocation site, not the leak location.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@51198 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index fd47f03..35f380e 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -25,6 +25,7 @@
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/STLExtras.h"
#include <ostream>
#include <sstream>
@@ -1740,6 +1741,7 @@
virtual void EmitWarnings(BugReporter& BR);
virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes);
virtual bool isLeak() const { return true; }
+ virtual bool isCached(BugReport& R);
};
//===---------===//
@@ -1772,6 +1774,8 @@
}
}
+ SymbolID getSymbol() const { return Sym; }
+
virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
ExplodedNode<ValueState>* N);
@@ -1963,6 +1967,49 @@
return P;
}
+static std::pair<ExplodedNode<ValueState>*,VarDecl*>
+GetAllocationSite(ExplodedNode<ValueState>* N, SymbolID Sym) {
+
+ typedef CFRefCount::RefBindings RefBindings;
+ ExplodedNode<ValueState>* Last = N;
+
+ // Find the first node that referred to the tracked symbol. We also
+ // try and find the first VarDecl the value was stored to.
+
+ VarDecl* FirstDecl = 0;
+
+ while (N) {
+ ValueState* St = N->getState();
+ RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
+ RefBindings::TreeTy* T = B.SlimFind(Sym);
+
+ if (!T)
+ break;
+
+ VarDecl* VD = 0;
+
+ // Determine if there is an LVal binding to the symbol.
+ for (ValueState::vb_iterator I=St->vb_begin(), E=St->vb_end(); I!=E; ++I) {
+ if (!isa<lval::SymbolVal>(I->second) // Is the value a symbol?
+ || cast<lval::SymbolVal>(I->second).getSymbol() != Sym)
+ continue;
+
+ if (VD) { // Multiple decls map to this symbol.
+ VD = 0;
+ break;
+ }
+
+ VD = I->first;
+ }
+
+ if (VD) FirstDecl = VD;
+
+ Last = N;
+ N = N->pred_empty() ? NULL : *(N->pred_begin());
+ }
+
+ return std::make_pair(Last, FirstDecl);
+}
PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
ExplodedNode<ValueState>* EndN) {
@@ -1984,50 +2031,16 @@
}
// We are a leak. Walk up the graph to get to the first node where the
- // symbol appeared.
-
- ExplodedNode<ValueState>* N = EndN;
- ExplodedNode<ValueState>* Last = N;
-
- // Find the first node that referred to the tracked symbol. We also
- // try and find the first VarDecl the value was stored to.
-
+ // symbol appeared, and also get the first VarDecl that tracked object
+ // is stored to.
+
+ ExplodedNode<ValueState>* AllocNode = 0;
VarDecl* FirstDecl = 0;
-
- while (N) {
- ValueState* St = N->getState();
- RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
- RefBindings::TreeTy* T = B.SlimFind(Sym);
-
- if (!T)
- break;
-
- VarDecl* VD = 0;
-
- // Determine if there is an LVal binding to the symbol.
- for (ValueState::vb_iterator I=St->vb_begin(), E=St->vb_end(); I!=E; ++I) {
- if (!isa<lval::SymbolVal>(I->second) // Is the value a symbol?
- || cast<lval::SymbolVal>(I->second).getSymbol() != Sym)
- continue;
-
- if (VD) { // Multiple decls map to this symbol.
- VD = 0;
- break;
- }
-
- VD = I->first;
- }
-
- if (VD) FirstDecl = VD;
-
- Last = N;
- N = N->pred_empty() ? NULL : *(N->pred_begin());
- }
+ llvm::tie(AllocNode, FirstDecl) = GetAllocationSite(EndN, Sym);
- // Get the allocate site.
-
- assert (Last);
- Stmt* FirstStmt = cast<PostStmt>(Last->getLocation()).getStmt();
+ // Get the allocate site.
+ assert (AllocNode);
+ Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
SourceManager& SMgr = BR.getContext().getSourceManager();
unsigned AllocLine = SMgr.getLogicalLineNumber(FirstStmt->getLocStart());
@@ -2128,6 +2141,23 @@
Nodes.push_back(I->first);
}
+bool Leak::isCached(BugReport& R) {
+
+ // 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 only a single path.
+
+ SymbolID Sym = static_cast<CFRefReport&>(R).getSymbol();
+
+ ExplodedNode<ValueState>* AllocNode =
+ GetAllocationSite(R.getEndNode(), Sym).first;
+
+ if (!AllocNode)
+ return false;
+
+ return BugTypeCacheLocation::isCached(AllocNode->getLocation());
+}
+
//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//