aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-03-16 23:24:20 +0000
committerAnna Zaks <ganna@apple.com>2012-03-16 23:24:20 +0000
commit56a938ff85a444eb3d30d2634d92ce5b1f6fae56 (patch)
tree9d85719ed51903e12e39c5f7d4db93f727f37763 /lib/StaticAnalyzer/Core
parent076add680e281709cf081052be0dcb822dc8f37d (diff)
[analyzer] Create symbol-aware stack hints (building upon r152837).
The symbol-aware stack hint combines the checker-provided message with the information about how the symbol was passed to the callee: as a parameter or a return value. For malloc, the generated messages look like this : "Returning from 'foo'; released memory via 1st parameter" "Returning from 'foo'; allocated memory via 1st parameter" "Returning from 'foo'; allocated memory returned" "Returning from 'foo'; reallocation of 1st parameter failed" (We are yet to handle cases when the symbol is a field in a struct or an array element.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152962 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp33
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp91
2 files changed, 111 insertions, 13 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index b59405bcd2..363a6dffee 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -380,22 +380,29 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
+typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*> StackDiagPair;
+typedef SmallVector<StackDiagPair, 6> StackDiagVector;
+
static void updateStackPiecesWithMessage(PathDiagnosticPiece *P,
- llvm::SmallVector<PathDiagnosticCallPiece*, 6> &CallStack) {
+ StackDiagVector &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)
+ if (ep->hasCallStackHint())
+ for (StackDiagVector::iterator I = CallStack.begin(),
+ E = CallStack.end(); I != E; ++I) {
+ PathDiagnosticCallPiece *CP = I->first;
+ const ExplodedNode *N = I->second;
+ StringRef stackMsg = ep->getCallStackMessage(N);
+
// 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);
+ if (!CP->hasCallStackMessage())
+ CP->setCallStackMessage(stackMsg);
+ }
}
}
@@ -410,7 +417,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
const ExplodedNode *NextNode = N->pred_empty()
? NULL : *(N->pred_begin());
- llvm::SmallVector<PathDiagnosticCallPiece*, 6> CallStack;
+ StackDiagVector CallStack;
while (NextNode) {
N = NextNode;
@@ -424,7 +431,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticCallPiece::construct(N, *CE, SMgr);
PD.getActivePath().push_front(C);
PD.pushActivePath(&C->path);
- CallStack.push_back(C);
+ CallStack.push_back(StackDiagPair(C, N));
continue;
}
@@ -446,7 +453,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
C->setCallee(*CE, SMgr);
if (!CallStack.empty()) {
- assert(CallStack.back() == C);
+ assert(CallStack.back().first == C);
CallStack.pop_back();
}
continue;
@@ -1047,7 +1054,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
const ExplodedNode *N) {
EdgeBuilder EB(PD, PDB);
const SourceManager& SM = PDB.getSourceManager();
- llvm::SmallVector<PathDiagnosticCallPiece*, 6> CallStack;
+ StackDiagVector CallStack;
const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
@@ -1068,7 +1075,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticCallPiece::construct(N, *CE, SM);
PD.getActivePath().push_front(C);
PD.pushActivePath(&C->path);
- CallStack.push_back(C);
+ CallStack.push_back(StackDiagPair(C, N));
break;
}
@@ -1104,7 +1111,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addContext(CE->getCallExpr());
if (!CallStack.empty()) {
- assert(CallStack.back() == C);
+ assert(CallStack.back().first == C);
CallStack.pop_back();
}
break;
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index cd08f9ceb7..2a2b9c615e 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -659,3 +659,94 @@ void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
ID.AddString(*I);
}
+
+StackHintGenerator::~StackHintGenerator() {}
+
+std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
+ ProgramPoint P = N->getLocation();
+ const CallExit *CExit = dyn_cast<CallExit>(&P);
+ assert(CExit && "Stack Hints should be constructed at CallExit points.");
+
+ const CallExpr *CE = dyn_cast_or_null<CallExpr>(CExit->getStmt());
+ if (!CE)
+ return "";
+
+ // Get the successor node to make sure the return statement is evaluated and
+ // CE is set to the result value.
+ N = *N->succ_begin();
+ if (!N)
+ return getMessageForSymbolNotFound();
+
+ // Check if one of the parameters are set to the interesting symbol.
+ ProgramStateRef State = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
+ unsigned ArgIndex = 0;
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(),
+ E = CE->arg_end(); I != E; ++I, ++ArgIndex){
+ SVal SV = State->getSVal(*I, LCtx);
+
+ // Check if the variable corresponding to the symbol is passed by value.
+ SymbolRef AS = SV.getAsLocSymbol();
+ if (AS == Sym) {
+ return getMessageForArg(*I, ArgIndex);
+ }
+
+ // Check if the parameter is a pointer to the symbol.
+ if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
+ SVal PSV = State->getSVal(Reg->getRegion());
+ SymbolRef AS = PSV.getAsLocSymbol();
+ if (AS == Sym) {
+ return getMessageForArg(*I, ArgIndex);
+ }
+ }
+ }
+
+ // Check if we are returning the interesting symbol.
+ SVal SV = State->getSVal(CE, LCtx);
+ SymbolRef RetSym = SV.getAsLocSymbol();
+ if (RetSym == Sym) {
+ return getMessageForReturn(CE);
+ }
+
+ return getMessageForSymbolNotFound();
+}
+
+/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
+/// some common place. (Same as HandleOrdinalModifier.)
+void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
+ llvm::raw_svector_ostream &Out) {
+ assert(ValNo != 0 && "ValNo must be strictly positive!");
+
+ // We could use text forms for the first N ordinals, but the numeric
+ // forms are actually nicer in diagnostics because they stand out.
+ Out << ValNo;
+
+ // It is critically important that we do this perfectly for
+ // user-written sequences with over 100 elements.
+ switch (ValNo % 100) {
+ case 11:
+ case 12:
+ case 13:
+ Out << "th"; return;
+ default:
+ switch (ValNo % 10) {
+ case 1: Out << "st"; return;
+ case 2: Out << "nd"; return;
+ case 3: Out << "rd"; return;
+ default: Out << "th"; return;
+ }
+ }
+}
+
+std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
+ unsigned ArgIndex) {
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << Msg << " via ";
+ // Printed parameters start at 1, not 0.
+ printOrdinal(++ArgIndex, os);
+ os << " parameter";
+
+ return os.str();
+}