aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp38
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp33
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp91
3 files changed, 142 insertions, 20 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index e071626eb6..2926fd5c04 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -243,6 +243,29 @@ private:
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR);
+ private:
+ class StackHintGeneratorForReallocationFailed
+ : public StackHintGeneratorForSymbol {
+ public:
+ StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
+ : StackHintGeneratorForSymbol(S, M) {}
+
+ virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) {
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "; reallocation of ";
+ // Printed parameters start at 1, not 0.
+ printOrdinal(++ArgIndex, os);
+ os << " parameter failed";
+
+ return os.str();
+ }
+
+ virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
+ return "; reallocation of returned value failed";
+ }
+ };
};
};
} // end anonymous namespace
@@ -1249,7 +1272,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
const Stmt *S = 0;
const char *Msg = 0;
- const char *StackMsg = 0;
+ StackHintGeneratorForSymbol *StackHint = 0;
// Retrieve the associated statement.
ProgramPoint ProgLoc = N->getLocation();
@@ -1269,14 +1292,15 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
if (Mode == Normal) {
if (isAllocated(RS, RSPrev, S)) {
Msg = "Memory is allocated";
- StackMsg = ", which allocated memory";
+ StackHint = new StackHintGeneratorForSymbol(Sym, "; allocated memory");
} else if (isReleased(RS, RSPrev, S)) {
Msg = "Memory is released";
- StackMsg = ", which released memory";
+ StackHint = new StackHintGeneratorForSymbol(Sym, "; released memory");
} else if (isReallocFailedCheck(RS, RSPrev, S)) {
Mode = ReallocationFailed;
Msg = "Reallocation failed";
- StackMsg = ", where reallocation failed";
+ StackHint = new StackHintGeneratorForReallocationFailed(Sym,
+ "; reallocation failed");
}
// We are in a special mode if a reallocation failed later in the path.
@@ -1296,18 +1320,18 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
if (!(FunName.equals("realloc") || FunName.equals("reallocf")))
return 0;
Msg = "Attempt to reallocate memory";
- StackMsg = ", which attempted to reallocate memory";
+ StackHint = new StackHintGeneratorForSymbol(Sym, "; reallocated memory");
Mode = Normal;
}
if (!Msg)
return 0;
- assert(StackMsg);
+ assert(StackHint);
// Generate the extra diagnostic.
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
- return new PathDiagnosticEventPiece(Pos, Msg, true, StackMsg);
+ return new PathDiagnosticEventPiece(Pos, Msg, true, StackHint);
}
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();
+}