[analyzer] Allow checkers to supply call stack diagnostic hints for the
BugVisitor DiagnosticPieces.
When checkers create a DiagnosticPieceEvent, they can supply an extra
string, which will be concatenated with the call exit message for every
call on the stack between the diagnostic event and the final bug report.
(This is a simple version, which could be/will be further enhanced.)
For example, this is used in Malloc checker to produce the ",
which allocated memory" in the following example:
static char *malloc_wrapper() { // 2. Entered call from 'use'
return malloc(12); // 3. Memory is allocated
}
void use() {
char *v;
v = malloc_wrapper(); // 1. Calling 'malloc_wrappers'
// 4. Returning from 'malloc_wrapper', which allocated memory
} // 5. Memory is never released; potential
memory leak
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152837 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 995ef26..0a0c1fd 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -380,6 +380,24 @@
//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
+static void updateStackPiecesWithMessage(PathDiagnosticPiece *P,
+ llvm::SmallVector<PathDiagnosticCallPiece*, 6> &CallStack) {
+ // If the piece contains a special message, add it to all the call
+ // pieces on the active stack.
+ if (PathDiagnosticEventPiece *ep =
+ dyn_cast<PathDiagnosticEventPiece>(P)) {
+ StringRef stackMsg = ep->getCallStackMessage();
+
+ if (!stackMsg.empty())
+ for (llvm::SmallVector<PathDiagnosticCallPiece*, 6>::iterator
+ I = CallStack.begin(), E = CallStack.end(); I != E; ++I)
+ // The last message on the path to final bug is the most important
+ // one. Since we traverse the path backwards, do not add the message
+ // if one has been previously added.
+ if (!(*I)->hasCallStackMessage())
+ (*I)->setCallStackMessage(stackMsg);
+ }
+}
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
@@ -391,6 +409,9 @@
const LocationContext *LC = PDB.LC;
const ExplodedNode *NextNode = N->pred_empty()
? NULL : *(N->pred_begin());
+
+ llvm::SmallVector<PathDiagnosticCallPiece*, 6> CallStack;
+
while (NextNode) {
N = NextNode;
PDB.LC = N->getLocationContext();
@@ -403,6 +424,7 @@
PathDiagnosticCallPiece::construct(N, *CE, SMgr);
PD.getActivePath().push_front(C);
PD.pushActivePath(&C->path);
+ CallStack.push_back(C);
continue;
}
@@ -423,6 +445,10 @@
C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
}
C->setCallee(*CE, SMgr);
+ if (!CallStack.empty()) {
+ assert(CallStack.back() == C);
+ CallStack.pop_back();
+ }
continue;
}
@@ -681,8 +707,10 @@
BugReport *R = PDB.getBugReport();
for (BugReport::visitor_iterator I = R->visitor_begin(),
E = R->visitor_end(); I!=E; ++I) {
- if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R))
+ if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) {
PD.getActivePath().push_front(p);
+ updateStackPiecesWithMessage(p, CallStack);
+ }
}
}
}
@@ -1019,6 +1047,7 @@
const ExplodedNode *N) {
EdgeBuilder EB(PD, PDB);
const SourceManager& SM = PDB.getSourceManager();
+ llvm::SmallVector<PathDiagnosticCallPiece*, 6> CallStack;
const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
@@ -1039,6 +1068,7 @@
PathDiagnosticCallPiece::construct(N, *CE, SM);
PD.getActivePath().push_front(C);
PD.pushActivePath(&C->path);
+ CallStack.push_back(C);
break;
}
@@ -1072,6 +1102,11 @@
}
C->setCallee(*CE, SM);
EB.addContext(CE->getCallExpr());
+
+ if (!CallStack.empty()) {
+ assert(CallStack.back() == C);
+ CallStack.pop_back();
+ }
break;
}
@@ -1147,6 +1182,8 @@
const PathDiagnosticLocation &Loc = p->getLocation();
EB.addEdge(Loc, true);
PD.getActivePath().push_front(p);
+ updateStackPiecesWithMessage(p, CallStack);
+
if (const Stmt *S = Loc.asStmt())
EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index ef815be..cd08f9c 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -572,6 +572,8 @@
Out << "Returning from '" << *ND << "'";
else
Out << "Returning to caller";
+ if (!CallStackMessage.empty())
+ Out << CallStackMessage;
return new PathDiagnosticEventPiece(callReturn, Out.str());
}