diff options
Diffstat (limited to 'lib')
19 files changed, 230 insertions, 266 deletions
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp index 0b11a459ce..ab66e9864f 100644 --- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp @@ -109,7 +109,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, const Expr *arg = *I; R->addRange(arg->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(errorNode, - arg)); + arg, R)); // Emit the bug report. C.EmitReport(R); } diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 1af43d1a33..dd4235af5e 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -411,7 +411,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, BugReport *report = new BugReport(*BT, description, N); report->addRange(Arg->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg, + report)); C.EmitReport(report); return; } diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 802103e396..639dd72e9d 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -252,7 +252,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(S->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S, + report)); C.EmitReport(report); return NULL; } diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index de48769d78..f6014317c8 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -72,7 +72,7 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, BugReport *R = new BugReport(*BT, BT->getName(), N); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetCalleeExpr(N))); + bugreporter::GetCalleeExpr(N), R)); C.EmitReport(R); } @@ -111,7 +111,8 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(argRange); if (argEx) - R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx, + R)); C.EmitReport(R); } return true; @@ -262,7 +263,8 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, new BugReport(*BT, BT->getName(), N); R->addRange(receiver->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - receiver)); + receiver, + R)); C.EmitReport(R); } return; @@ -308,7 +310,8 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, if (const Expr *receiver = msg.getInstanceReceiver()) { report->addRange(receiver->getSourceRange()); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - receiver)); + receiver, + report)); } C.EmitReport(report); } diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 7e4761cdf8..81a27451cb 100644 --- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -34,28 +34,35 @@ public: void checkLocation(SVal location, bool isLoad, const Stmt* S, CheckerContext &C) const; - static void AddDerefSource(raw_ostream &os, + static const MemRegion *AddDerefSource(raw_ostream &os, SmallVectorImpl<SourceRange> &Ranges, - const Expr *Ex, bool loadedFrom = false); + const Expr *Ex, const ProgramState *state, + const LocationContext *LCtx, + bool loadedFrom = false); }; } // end anonymous namespace -void DereferenceChecker::AddDerefSource(raw_ostream &os, - SmallVectorImpl<SourceRange> &Ranges, - const Expr *Ex, - bool loadedFrom) { +const MemRegion * +DereferenceChecker::AddDerefSource(raw_ostream &os, + SmallVectorImpl<SourceRange> &Ranges, + const Expr *Ex, + const ProgramState *state, + const LocationContext *LCtx, + bool loadedFrom) { Ex = Ex->IgnoreParenLValueCasts(); + const MemRegion *sourceR = 0; switch (Ex->getStmtClass()) { default: - return; + break; case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast<DeclRefExpr>(Ex); if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { os << " (" << (loadedFrom ? "loaded from" : "from") << " variable '" << VD->getName() << "')"; Ranges.push_back(DR->getSourceRange()); + sourceR = state->getLValue(VD, LCtx).getAsRegion(); } - return; + break; } case Stmt::MemberExprClass: { const MemberExpr *ME = cast<MemberExpr>(Ex); @@ -66,6 +73,7 @@ void DereferenceChecker::AddDerefSource(raw_ostream &os, break; } } + return sourceR; } void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -79,7 +87,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetDerefExpr(N))); + bugreporter::GetDerefExpr(N), report)); C.EmitReport(report); } return; @@ -92,6 +100,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, return; ProgramStateRef state = C.getState(); + const LocationContext *LCtx = C.getLocationContext(); ProgramStateRef notNullState, nullState; llvm::tie(notNullState, nullState) = state->assume(location); @@ -115,13 +124,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, // that syntactically caused the load. if (const Expr *expr = dyn_cast<Expr>(S)) S = expr->IgnoreParenLValueCasts(); + + const MemRegion *sourceR = 0; switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { llvm::raw_svector_ostream os(buf); os << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts()); + sourceR = + AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), + state.getPtr(), LCtx); os << " results in a null pointer dereference"; break; } @@ -129,7 +142,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, llvm::raw_svector_ostream os(buf); os << "Dereference of null pointer"; const UnaryOperator *U = cast<UnaryOperator>(S); - AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true); + sourceR = + AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), + state.getPtr(), LCtx, true); break; } case Stmt::MemberExprClass: { @@ -138,7 +153,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, llvm::raw_svector_ostream os(buf); os << "Access to field '" << M->getMemberNameInfo() << "' results in a dereference of a null pointer"; - AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true); + sourceR = + AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), + state.getPtr(), LCtx, true); } break; } @@ -165,12 +182,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, N); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetDerefExpr(N))); + bugreporter::GetDerefExpr(N), report)); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) report->addRange(*I); + if (sourceR) { + report->markInteresting(sourceR); + report->markInteresting(state->getRawSVal(loc::MemRegionVal(sourceR))); + } + C.EmitReport(report); return; } diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index ca71ca33a1..2627f0c982 100644 --- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -43,8 +43,7 @@ void DivZeroChecker::reportBug(const char *Msg, new BugReport(*BT, Msg, N); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetDenomExpr(N))); - + bugreporter::GetDenomExpr(N), R)); C.EmitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index b96bc66b6f..1b8dd6874c 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -121,6 +121,12 @@ private: SValBuilder &Builder) const { return definitelyReturnedError(RetSym, State, Builder, true); } + + /// Mark an AllocationPair interesting for diagnostic reporting. + void markInteresting(BugReport *R, const AllocationPair &AP) const { + R->markInteresting(AP.first); + R->markInteresting(AP.second->Region); + } /// The bug visitor which allows us to print extra diagnostics along the /// BugReport path. For example, showing the allocation site of the leaked @@ -282,6 +288,7 @@ void MacOSKeychainAPIChecker:: BugReport *Report = new BugReport(*BT, os.str(), N); Report->addVisitor(new SecKeychainBugVisitor(AP.first)); Report->addRange(ArgExpr->getSourceRange()); + markInteresting(Report, AP); C.EmitReport(Report); } @@ -318,6 +325,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, BugReport *Report = new BugReport(*BT, os.str(), N); Report->addVisitor(new SecKeychainBugVisitor(V)); Report->addRange(ArgExpr->getSourceRange()); + Report->markInteresting(AS->Region); C.EmitReport(Report); } } @@ -369,6 +377,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, BugReport *Report = new BugReport(*BT, "Trying to free data which has not been allocated.", N); Report->addRange(ArgExpr->getSourceRange()); + if (AS) + Report->markInteresting(AS->Region); C.EmitReport(Report); return; } @@ -432,6 +442,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, "Only call free if a valid (non-NULL) buffer was returned.", N); Report->addVisitor(new SecKeychainBugVisitor(ArgSM)); Report->addRange(ArgExpr->getSourceRange()); + Report->markInteresting(AS->Region); C.EmitReport(Report); return; } @@ -550,6 +561,7 @@ BugReport *MacOSKeychainAPIChecker:: BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing); Report->addVisitor(new SecKeychainBugVisitor(AP.first)); + markInteresting(Report, AP); return Report; } diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c9f717059e..3f0d3d456e 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -535,6 +535,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, BugReport *R = new BugReport(*BT_DoubleFree, "Attempt to free released memory", N); R->addRange(ArgExpr->getSourceRange()); + R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); } @@ -667,6 +668,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, } BugReport *R = new BugReport(*BT_BadFree, os.str(), N); + R->markInteresting(MR); R->addRange(range); C.EmitReport(R); } @@ -820,6 +822,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, BugReport *R = new BugReport(*BT_Leak, "Memory is never released; potential memory leak", N, LocUsedForUniqueing); + R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); } @@ -964,6 +967,7 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, "Use of memory after it is freed",N); if (S) R->addRange(S->getSourceRange()); + R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); return true; diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index d70fdfd8e8..25caf98b6d 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -50,7 +50,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, "for @synchronized")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, + report)); C.EmitReport(report); } return; @@ -73,7 +74,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, "(no synchronization will occur)")); BugReport *report = new BugReport(*BT_null, BT_null->getDescription(), N); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, + report)); C.EmitReport(report); return; diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index f7dd6c2127..a59d1e4e4c 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -2165,9 +2165,7 @@ PathDiagnosticPiece* CFRefReportVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *EndN, BugReport &BR) { - // Tell the BugReporterContext to report cases when the tracked symbol is - // assigned to different variables, etc. - BRC.addNotableSymbol(Sym); + BR.markInteresting(Sym); return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); } @@ -2178,7 +2176,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. - BRC.addNotableSymbol(Sym); + BR.markInteresting(Sym); // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index c83d63d00a..7b1f0b139c 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -54,7 +54,8 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, new BugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE, + report)); C.EmitReport(report); } diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index e826a114e7..a30f6d5328 100644 --- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -99,7 +99,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, // Emit the bug report. BugReport *R = new BugReport(*BT, BT->getDescription(), N); - R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, R)); R->addRange(Ex->getSourceRange()); Ctx.EmitReport(R); diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 3161a21c93..c3c9ed7234 100644 --- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -76,10 +76,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, BugReport *report = new BugReport(*BT, OS.str(), N); if (Ex) { report->addRange(Ex->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, + report)); } else - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B, + report)); C.EmitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index 9b9e4d5e36..0297c4eb14 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -43,7 +43,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(A->getIdx()->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - A->getIdx())); + A->getIdx(), + R)); C.EmitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 840ae3d2ad..78f7fa61b2 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -78,7 +78,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); - R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex, R)); } C.EmitReport(R); } diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 2211940d65..e68ab2a8b2 100644 --- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -224,7 +224,8 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, BugReport *report = new BugReport(*BT_mallocZero, os.str(), N); report->addRange(arg->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg, + report)); C.EmitReport(report); return true; diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 72b68c58bf..38c9cc1f33 100644 --- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -69,7 +69,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(SizeE->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE, + report)); C.EmitReport(report); return; } 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 B |