aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp240
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp136
2 files changed, 146 insertions, 230 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 53fedaf2a1..4ada636e8e 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -148,8 +148,9 @@ static bool RemoveUneededCalls(PathPieces &pieces) {
PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece);
// We never throw away an event, but we do throw it away wholesale
// as part of a path if we throw the entire path away.
- if (!event->isPrunable())
- containsSomethingInteresting = true;
+ if (event->isPrunable())
+ continue;
+ containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::ControlFlow:
@@ -377,190 +378,6 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
}
//===----------------------------------------------------------------------===//
-// ScanNotableSymbols: closure-like callback for scanning Store bindings.
-//===----------------------------------------------------------------------===//
-
-static const VarDecl* GetMostRecentVarDeclBinding(const ExplodedNode *N,
- ProgramStateManager& VMgr,
- SVal X) {
-
- for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
-
- ProgramPoint P = N->getLocation();
-
- if (!isa<PostStmt>(P))
- continue;
-
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
-
- if (!DR)
- continue;
-
- SVal Y = N->getState()->getSVal(DR, N->getLocationContext());
-
- if (X != Y)
- continue;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
-
- if (!VD)
- continue;
-
- return VD;
- }
-
- return 0;
-}
-
-namespace {
-class NotableSymbolHandler
-: public StoreManager::BindingsHandler {
-
- SymbolRef Sym;
- ProgramStateRef PrevSt;
- const Stmt *S;
- ProgramStateManager& VMgr;
- const ExplodedNode *Pred;
- PathDiagnostic& PD;
- BugReporter& BR;
-
-public:
-
- NotableSymbolHandler(SymbolRef sym,
- ProgramStateRef prevst,
- const Stmt *s,
- ProgramStateManager& vmgr,
- const ExplodedNode *pred,
- PathDiagnostic& pd,
- BugReporter& br)
- : Sym(sym),
- PrevSt(prevst),
- S(s),
- VMgr(vmgr),
- Pred(pred),
- PD(pd),
- BR(br) {}
-
- bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
- SVal V) {
-
- SymbolRef ScanSym = V.getAsSymbol();
-
- if (ScanSym != Sym)
- return true;
-
- // Check if the previous state has this binding.
- SVal X = PrevSt->getSVal(loc::MemRegionVal(R));
-
- if (X == V) // Same binding?
- return true;
-
- // Different binding. Only handle assignments for now. We don't pull
- // this check out of the loop because we will eventually handle other
- // cases.
-
- VarDecl *VD = 0;
-
- if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
- if (!B->isAssignmentOp())
- return true;
-
- // What variable did we assign to?
- DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
-
- if (!DR)
- return true;
-
- VD = dyn_cast<VarDecl>(DR->getDecl());
- }
- else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
- // FIXME: Eventually CFGs won't have DeclStmts. Right now we
- // assume that each DeclStmt has a single Decl. This invariant
- // holds by construction in the CFG.
- VD = dyn_cast<VarDecl>(*DS->decl_begin());
- }
-
- if (!VD)
- return true;
-
- // What is the most recently referenced variable with this binding?
- const VarDecl *MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
-
- if (!MostRecent)
- return true;
-
- // Create the diagnostic.
- if (Loc::isLocType(VD->getType())) {
- SmallString<64> buf;
- llvm::raw_svector_ostream os(buf);
- os << '\'' << *VD << "' now aliases '" << *MostRecent << '\'';
- PathDiagnosticLocation L =
- PathDiagnosticLocation::createBegin(S, BR.getSourceManager(),
- Pred->getLocationContext());
- PD.getActivePath().push_front(new PathDiagnosticEventPiece(L, os.str()));
- }
-
- return true;
- }
-};
-}
-
-static void HandleNotableSymbol(const ExplodedNode *N,
- const Stmt *S,
- SymbolRef Sym, BugReporter& BR,
- PathDiagnostic& PD) {
-
- const ExplodedNode *Pred = N->pred_empty() ? 0 : *N->pred_begin();
- ProgramStateRef PrevSt = Pred ? Pred->getState() : 0;
-
- if (!PrevSt)
- return;
-
- // Look at the region bindings of the current state that map to the
- // specified symbol. Are any of them not in the previous state?
- ProgramStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
- NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
- cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
-}
-
-namespace {
-class ScanNotableSymbols
-: public StoreManager::BindingsHandler {
-
- llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
- const ExplodedNode *N;
- const Stmt *S;
- GRBugReporter& BR;
- PathDiagnostic& PD;
-
-public:
- ScanNotableSymbols(const ExplodedNode *n, const Stmt *s,
- GRBugReporter& br, PathDiagnostic& pd)
- : N(n), S(s), BR(br), PD(pd) {}
-
- bool HandleBinding(StoreManager& SMgr, Store store,
- const MemRegion* R, SVal V) {
-
- SymbolRef ScanSym = V.getAsSymbol();
-
- if (!ScanSym)
- return true;
-
- if (!BR.isNotable(ScanSym))
- return true;
-
- if (AlreadyProcessed.count(ScanSym))
- return true;
-
- AlreadyProcessed.insert(ScanSym);
-
- HandleNotableSymbol(N, S, ScanSym, BR, PD);
- return true;
- }
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
@@ -866,13 +683,6 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PD.getActivePath().push_front(p);
}
}
-
- if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- // Scan the region bindings, and see if a "notable" symbol has a new
- // lval binding.
- ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
- PDB.getStateManager().iterBindings(N->getState(), SNS);
- }
}
// After constructing the full PathDiagnostic, do a pass over it to compact
@@ -1400,6 +1210,50 @@ void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
}
}
+void BugReport::markInteresting(SymbolRef sym) {
+ if (!sym)
+ return;
+ interestingSymbols.insert(sym);
+}
+
+void BugReport::markInteresting(const MemRegion *R) {
+ if (!R)
+ return;
+ R = R->getBaseRegion();
+ interestingRegions.insert(R);
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ interestingSymbols.insert(SR->getSymbol());
+}
+
+void BugReport::markInteresting(SVal V) {
+ markInteresting(V.getAsRegion());
+ markInteresting(V.getAsSymbol());
+}
+
+bool BugReport::isInteresting(SVal V) const {
+ return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol());
+}
+
+bool BugReport::isInteresting(SymbolRef sym) const {
+ if (!sym)
+ return false;
+ return interestingSymbols.count(sym);
+}
+
+bool BugReport::isInteresting(const MemRegion *R) const {
+ if (!R)
+ return false;
+ R = R->getBaseRegion();
+ bool b = interestingRegions.count(R);
+ if (b)
+ return true;
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ return interestingSymbols.count(SR->getSymbol());
+ return false;
+}
+
+
const Stmt *BugReport::getStmt() const {
if (!ErrorNode)
return 0;
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 1d29d5ff0a..09a9b41eae 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -287,7 +287,8 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
BugReporterVisitor *
bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
- const Stmt *S) {
+ const Stmt *S,
+ BugReport *report) {
if (!S || !N)
return 0;
@@ -309,17 +310,19 @@ bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
ProgramStateRef state = N->getState();
- // Walk through lvalue-to-rvalue conversions.
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const VarRegion *R =
- StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
-
- // What did we load?
- SVal V = state->getSVal(loc::MemRegionVal(R));
+ // Walk through lvalue-to-rvalue conversions.
+ const Expr *Ex = dyn_cast<Expr>(S);
+ if (Ex) {
+ Ex = Ex->IgnoreParenLValueCasts();
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ const VarRegion *R =
+ StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
- if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
- || V.isUndef()) {
+ // What did we load?
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ report->markInteresting(R);
+ report->markInteresting(V);
return new FindLastStoreBRVisitor(V, R);
}
}
@@ -339,7 +342,7 @@ bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
}
if (R) {
- assert(isa<SymbolicRegion>(R));
+ report->markInteresting(R);
return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
}
}
@@ -386,7 +389,7 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
// The receiver was nil, and hence the method was skipped.
// Register a BugReporterVisitor to issue a message telling us how
// the receiver was null.
- BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver));
+ BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver, &BR));
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
@@ -439,7 +442,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR);
if (PathDiagnosticEventPiece *ev =
dyn_cast_or_null<PathDiagnosticEventPiece>(piece))
- ev->setPrunable(true);
+ ev->setPrunable(true, /* override */ false);
return piece;
}
@@ -465,7 +468,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) {
const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminator())
- return VisitTerminator(term, N, srcBlk, BE->getDst(), BRC);
+ return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
return 0;
}
@@ -479,10 +482,10 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
const ProgramPointTag *tag = PS->getTag();
if (tag == tags.first)
return VisitTrueTest(cast<Expr>(PS->getStmt()), true,
- BRC, N->getLocationContext());
+ BRC, BR, N);
if (tag == tags.second)
return VisitTrueTest(cast<Expr>(PS->getStmt()), false,
- BRC, N->getLocationContext());
+ BRC, BR, N);
return 0;
}
@@ -495,6 +498,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
const ExplodedNode *N,
const CFGBlock *srcBlk,
const CFGBlock *dstBlk,
+ BugReport &R,
BugReporterContext &BRC) {
const Expr *Cond = 0;
@@ -513,14 +517,15 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
assert(srcBlk->succ_size() == 2);
const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
- tookTrue, BRC, N->getLocationContext());
+ tookTrue, BRC, R, N);
}
PathDiagnosticPiece *
ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &R,
+ const ExplodedNode *N) {
const Expr *Ex = Cond;
@@ -530,9 +535,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
default:
return 0;
case Stmt::BinaryOperatorClass:
- return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, LC);
+ return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC,
+ R, N);
case Stmt::DeclRefExprClass:
- return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, LC);
+ return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC,
+ R, N);
case Stmt::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(Ex);
if (UO->getOpcode() == UO_LNot) {
@@ -547,14 +554,31 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
}
bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out,
- BugReporterContext &BRC) {
+ BugReporterContext &BRC,
+ BugReport &report,
+ const ExplodedNode *N,
+ llvm::Optional<bool> &prunable) {
const Expr *OriginalExpr = Ex;
Ex = Ex->IgnoreParenCasts();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
const bool quotes = isa<VarDecl>(DR->getDecl());
- if (quotes)
+ if (quotes) {
Out << '\'';
+ const LocationContext *LCtx = N->getLocationContext();
+ const ProgramState *state = N->getState().getPtr();
+ if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
+ LCtx).getAsRegion()) {
+ if (report.isInteresting(R))
+ prunable = false;
+ else {
+ const ProgramState *state = N->getState().getPtr();
+ SVal V = state->getSVal(R);
+ if (report.isInteresting(V))
+ prunable = false;
+ }
+ }
+ }
Out << DR->getDecl()->getDeclName().getAsString();
if (quotes)
Out << '\'';
@@ -588,15 +612,19 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const BinaryOperator *BExpr,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &R,
+ const ExplodedNode *N) {
bool shouldInvert = false;
+ llvm::Optional<bool> shouldPrune;
SmallString<128> LhsString, RhsString;
{
- llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
- const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC);
- const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC);
+ llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
+ const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC, R, N,
+ shouldPrune);
+ const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N,
+ shouldPrune);
shouldInvert = !isVarLHS && isVarRHS;
}
@@ -607,7 +635,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
// For assignment operators, all that we care about is that the LHS
// evaluates to "true" or "false".
return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue,
- BRC, LC);
+ BRC, R, N);
}
// For non-assignment operations, we require that we can understand
@@ -655,9 +683,13 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
}
Out << (shouldInvert ? LhsString : RhsString);
-
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
- return new PathDiagnosticEventPiece(Loc, Out.str());
+ const LocationContext *LCtx = N->getLocationContext();
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
+ PathDiagnosticEventPiece *event =
+ new PathDiagnosticEventPiece(Loc, Out.str());
+ if (shouldPrune.hasValue())
+ event->setPrunable(shouldPrune.getValue());
+ return event;
}
PathDiagnosticPiece *
@@ -665,7 +697,8 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
const Expr *CondVarExpr,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &report,
+ const ExplodedNode *N) {
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
Out << "Assuming " << LhsString << " is ";
@@ -683,8 +716,22 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
else
return 0;
- PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LC);
- return new PathDiagnosticEventPiece(Loc, Out.str());
+ const LocationContext *LCtx = N->getLocationContext();
+ PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
+ PathDiagnosticEventPiece *event =
+ new PathDiagnosticEventPiece(Loc, Out.str());
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ const ProgramState *state = N->getState().getPtr();
+ if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
+ if (report.isInteresting(R))
+ event->setPrunable(false);
+ }
+ }
+ }
+
+ return event;
}
PathDiagnosticPiece *
@@ -692,7 +739,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const DeclRefExpr *DR,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &report,
+ const ExplodedNode *N) {
const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
if (!VD)
@@ -716,7 +764,21 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
else
return 0;
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
- return new PathDiagnosticEventPiece(Loc, Out.str());
+ const LocationContext *LCtx = N->getLocationContext();
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
+ PathDiagnosticEventPiece *event =
+ new PathDiagnosticEventPiece(Loc, Out.str());
+
+ const ProgramState *state = N->getState().getPtr();
+ if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
+ if (report.isInteresting(R))
+ event->setPrunable(false);
+ else {
+ SVal V = state->getSVal(R);
+ if (report.isInteresting(V))
+ event->setPrunable(false);
+ }
+ }
+ return event;
}