diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporter.cpp | 240 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 136 |
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; } |