diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-09-09 19:05:34 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-09-09 19:05:34 +0000 |
commit | 61f52bd3c524268e25b48a1ed3730aedd6cc8374 (patch) | |
tree | d0404a2d0ecdd0b4d84ee37f6e27ab69d543cf5c /lib/Checker/BugReporter.cpp | |
parent | 80c26f44a6f8d859a2a3babb06bd3ca8d86f2623 (diff) |
Use FindReportInEquivalenceClass to identify all the nodes used for the trimmed graph (in BugReporter). This fixes a problem where a leak that happened to occur on both an exit() path and a non-exit() path was getting reported with the exit() path (which users don't care about).
This fixes:
<rdar://problem/8331641> leak reports should not show paths that end with exit() (but ones that don't end with exit())
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113524 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/BugReporter.cpp')
-rw-r--r-- | lib/Checker/BugReporter.cpp | 88 |
1 files changed, 54 insertions, 34 deletions
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index bffbd52b7d..5043d90526 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -1567,23 +1567,18 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { } void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, - BugReportEquivClass& EQ) { + BugReportEquivClass& EQ, + llvm::SmallVectorImpl<const ExplodedNode *> &Nodes) { - std::vector<const ExplodedNode*> Nodes; - for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) { - const ExplodedNode* N = I->getEndNode(); - if (N) Nodes.push_back(N); - } - - if (Nodes.empty()) - return; + assert(!Nodes.empty()); // Construct a new graph that contains only a single path from the error // node to a root. const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>, std::pair<ExplodedNode*, unsigned> >& - GPair = MakeReportGraph(&getGraph(), &Nodes[0], &Nodes[0] + Nodes.size()); + GPair = MakeReportGraph(&getGraph(), &Nodes[0], + Nodes.data() + Nodes.size()); // Find the BugReport with the original location. BugReport *R = 0; @@ -1657,21 +1652,36 @@ struct FRIEC_WLItem { }; } -static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { +static BugReport * +FindReportInEquivalenceClass(BugReportEquivClass& EQ, + llvm::SmallVectorImpl<const ExplodedNode*> &Nodes) { + BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end(); assert(I != E); BugReport *R = *I; BugType& BT = R->getBugType(); - - if (!BT.isSuppressOnSink()) + + // If we don't need to suppress any of the nodes because they are post-dominated + // by a sink, simply add all the nodes in the equivalence class to 'Nodes'. + if (!BT.isSuppressOnSink()) { + for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) { + const ExplodedNode* N = I->getEndNode(); + if (N) { + R = *I; + Nodes.push_back(N); + } + } return R; - + } + // For bug reports that should be suppressed when all paths are post-dominated // by a sink node, iterate through the reports in the equivalence class // until we find one that isn't post-dominated (if one exists). We use a // DFS traversal of the ExplodedGraph to find a non-sink node. We could write // this as a recursive function, but we don't want to risk blowing out the // stack for very long paths. + BugReport *ExampleReport = 0; + for (; I != E; ++I) { R = *I; const ExplodedNode *N = R->getEndNode(); @@ -1682,12 +1692,17 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { if (N->isSink()) { assert(false && "BugType::isSuppressSink() should not be 'true' for sink end nodes"); - return R; + return 0; } - - if (N->succ_empty()) - return R; - + + // No successors? By definition this nodes isn't post-dominated by a sink. + if (N->succ_empty()) { + Nodes.push_back(N); + if (!ExampleReport) + ExampleReport = R; + continue; + } + // At this point we know that 'N' is not a sink and it has at least one // successor. Use a DFS worklist to find a non-sink end-of-path node. typedef FRIEC_WLItem WLItem; @@ -1706,15 +1721,17 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { const ExplodedNode *Succ = *WI.I; // End-of-path node? if (Succ->succ_empty()) { - // If we found an end-of-path node that is not a sink, then return - // this report. - if (!Succ->isSink()) - return R; - + // If we found an end-of-path node that is not a sink. + if (!Succ->isSink()) { + Nodes.push_back(N); + if (!ExampleReport) + ExampleReport = R; + WL.clear(); + break; + } // Found a sink? Continue on to the next successor. continue; } - // Mark the successor as visited. If it hasn't been explored, // enqueue it to the DFS worklist. unsigned &mark = Visited[Succ]; @@ -1724,17 +1741,18 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { break; } } - - if (&WL.back() == &WI) + + // The worklist may have been cleared at this point. First + // check if it is empty before checking the last item. + if (!WL.empty() && &WL.back() == &WI) WL.pop_back(); } } - - // If we reach here, the end nodes for all reports in the equivalence - // class are post-dominated by a sink node. - return NULL; -} + // ExampleReport will be NULL if all the nodes in the equivalence class + // were post-dominated by sinks. + return ExampleReport; +} //===----------------------------------------------------------------------===// // DiagnosticCache. This is a hack to cache analyzer diagnostics. It @@ -1780,7 +1798,8 @@ static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) { } void BugReporter::FlushReport(BugReportEquivClass& EQ) { - BugReport *R = FindReportInEquivalenceClass(EQ); + llvm::SmallVector<const ExplodedNode*, 10> Nodes; + BugReport *R = FindReportInEquivalenceClass(EQ, Nodes); if (!R) return; @@ -1797,7 +1816,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { ? R->getDescription() : R->getShortDescription(), BT.getCategory())); - GeneratePathDiagnostic(*D.get(), EQ); + if (!Nodes.empty()) + GeneratePathDiagnostic(*D.get(), EQ, Nodes); if (IsCachedDiagnostic(R, D.get())) return; |