зеркало из https://github.com/microsoft/clang-1.git
Improve leak diagnostics to not report a leak on the same line where
the object was last used. This can be confusing to users. For example: // 'y' is leaked x = foo(y); instead: x = foo(y); // 'y' is leaked git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50661 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
ce48e00a35
Коммит
e28565b994
|
@ -1707,10 +1707,10 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N,
|
||||||
}
|
}
|
||||||
|
|
||||||
PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
|
PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
|
||||||
ExplodedNode<ValueState>* N) {
|
ExplodedNode<ValueState>* EndN) {
|
||||||
|
|
||||||
if (!getBugType().isLeak())
|
if (!getBugType().isLeak())
|
||||||
return RangedBugReport::getEndPath(BR, N);
|
return RangedBugReport::getEndPath(BR, EndN);
|
||||||
|
|
||||||
typedef CFRefCount::RefBindings RefBindings;
|
typedef CFRefCount::RefBindings RefBindings;
|
||||||
|
|
||||||
|
@ -1718,7 +1718,7 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
|
||||||
unsigned long RetCount = 0;
|
unsigned long RetCount = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
ValueState* St = N->getState();
|
ValueState* St = EndN->getState();
|
||||||
RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
|
RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
|
||||||
RefBindings::TreeTy* T = B.SlimFind(Sym);
|
RefBindings::TreeTy* T = B.SlimFind(Sym);
|
||||||
assert (T);
|
assert (T);
|
||||||
|
@ -1728,6 +1728,7 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
|
||||||
// We are a leak. Walk up the graph to get to the first node where the
|
// We are a leak. Walk up the graph to get to the first node where the
|
||||||
// symbol appeared.
|
// symbol appeared.
|
||||||
|
|
||||||
|
ExplodedNode<ValueState>* N = EndN;
|
||||||
ExplodedNode<ValueState>* Last = N;
|
ExplodedNode<ValueState>* Last = N;
|
||||||
|
|
||||||
// Find the first node that referred to the tracked symbol. We also
|
// Find the first node that referred to the tracked symbol. We also
|
||||||
|
@ -1765,17 +1766,85 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
|
||||||
N = N->pred_empty() ? NULL : *(N->pred_begin());
|
N = N->pred_empty() ? NULL : *(N->pred_begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the location.
|
// Get the allocate site.
|
||||||
|
|
||||||
assert (Last);
|
assert (Last);
|
||||||
Stmt* FirstStmt = cast<PostStmt>(Last->getLocation()).getStmt();
|
Stmt* FirstStmt = cast<PostStmt>(Last->getLocation()).getStmt();
|
||||||
|
|
||||||
unsigned Line =
|
SourceManager& SMgr = BR.getContext().getSourceManager();
|
||||||
BR.getSourceManager().getLogicalLineNumber(FirstStmt->getLocStart());
|
unsigned AllocLine = SMgr.getLogicalLineNumber(FirstStmt->getLocStart());
|
||||||
|
|
||||||
|
// Get the leak site. We may have multiple ExplodedNodes (one with the
|
||||||
|
// leak) that occur on the same line number; if the node with the leak
|
||||||
|
// has any immediate predecessor nodes with the same line number, find
|
||||||
|
// any transitive-successors that have a different statement and use that
|
||||||
|
// line number instead. This avoids emiting a diagnostic like:
|
||||||
|
//
|
||||||
|
// // 'y' is leaked.
|
||||||
|
// int x = foo(y);
|
||||||
|
//
|
||||||
|
// instead we want:
|
||||||
|
//
|
||||||
|
// int x = foo(y);
|
||||||
|
// // 'y' is leaked.
|
||||||
|
|
||||||
|
Stmt* S = getStmt(BR); // This is the statement where the leak occured.
|
||||||
|
assert (S);
|
||||||
|
unsigned EndLine = SMgr.getLogicalLineNumber(S->getLocStart());
|
||||||
|
|
||||||
|
// Look in the *trimmed* graph at the immediate predecessor of EndN. Does
|
||||||
|
// it occur on the same line?
|
||||||
|
|
||||||
|
assert (!EndN->pred_empty()); // Not possible to have 0 predecessors.
|
||||||
|
N = *(EndN->pred_begin());
|
||||||
|
|
||||||
|
do {
|
||||||
|
ProgramPoint P = N->getLocation();
|
||||||
|
|
||||||
|
if (!isa<PostStmt>(P))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Predecessor at same line?
|
||||||
|
|
||||||
|
Stmt* SPred = cast<PostStmt>(P).getStmt();
|
||||||
|
|
||||||
|
if (SMgr.getLogicalLineNumber(SPred->getLocStart()) != EndLine)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// The predecessor (where the object was not yet leaked) is a statement
|
||||||
|
// on the same line. Get the first successor statement that appears
|
||||||
|
// on a different line. For this operation, we can traverse the
|
||||||
|
// non-trimmed graph.
|
||||||
|
|
||||||
|
N = getEndNode(); // This is the node where the leak occured in the
|
||||||
|
// original graph.
|
||||||
|
|
||||||
|
while (!N->succ_empty()) {
|
||||||
|
|
||||||
|
N = *(N->succ_begin());
|
||||||
|
ProgramPoint P = N->getLocation();
|
||||||
|
|
||||||
|
if (!isa<PostStmt>(P))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Stmt* SSucc = cast<PostStmt>(P).getStmt();
|
||||||
|
|
||||||
|
if (SMgr.getLogicalLineNumber(SSucc->getLocStart()) != EndLine) {
|
||||||
|
S = SSucc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (false);
|
||||||
|
|
||||||
|
// Construct the location.
|
||||||
|
|
||||||
|
FullSourceLoc L(S->getLocStart(), SMgr);
|
||||||
|
|
||||||
|
// Generate the diagnostic.
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
||||||
os << "Object allocated on line " << Line;
|
os << "Object allocated on line " << AllocLine;
|
||||||
|
|
||||||
if (FirstDecl)
|
if (FirstDecl)
|
||||||
os << " and stored into '" << FirstDecl->getName() << '\'';
|
os << " and stored into '" << FirstDecl->getName() << '\'';
|
||||||
|
@ -1783,12 +1852,7 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
|
||||||
os << " is no longer referenced after this point and has a retain count of +"
|
os << " is no longer referenced after this point and has a retain count of +"
|
||||||
<< RetCount << " (object leaked).";
|
<< RetCount << " (object leaked).";
|
||||||
|
|
||||||
Stmt* S = getStmt(BR);
|
return new PathDiagnosticPiece(L, os.str());
|
||||||
assert (S);
|
|
||||||
FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
|
|
||||||
PathDiagnosticPiece* P = new PathDiagnosticPiece(L, os.str());
|
|
||||||
|
|
||||||
return P;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UseAfterRelease::EmitWarnings(BugReporter& BR) {
|
void UseAfterRelease::EmitWarnings(BugReporter& BR) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче