From 4e99426629400ac74ba12dd6c59a5b0c62b5390d Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Tue, 25 Jul 2017 09:25:10 +0000 Subject: [analyzer] Further improve suppress-on-sink behavior in incomplete analyses. If a certain memory leak (or other similar bug) found by the analyzer is known to be happening only before abnormal termination of the program ("sink", eg. assertion failure in the code under analysis, or another bug that introduces undefined behavior), such leak warning is discarded. However, if the analysis has never reaches completion (due to complexity of the code), it may be failing to notice the sink. This commit further extends the partial solution introduced in r290341 to cover cases when a complicated control flow occurs before encountering a no-return statement (which anyway inevitably leads to such statement(s)) by traversing the respective section of the CFG in a depth-first manner. A complete solution still seems elusive. rdar://problem/28157554 Differential Revision: https://reviews.llvm.org/D35673 llvm-svn: 308957 --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 44 +++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'clang/lib/StaticAnalyzer/Core/BugReporter.cpp') diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index d8fca00681b..a306462605f 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3310,6 +3310,45 @@ static const CFGBlock *findBlockForNode(const ExplodedNode *N) { return nullptr; } +static bool isDominatedByNoReturnBlocks(const ExplodedNode *N) { + const CFG &Cfg = N->getCFG(); + + const CFGBlock *StartBlk = findBlockForNode(N); + if (!StartBlk) + return false; + if (StartBlk->hasNoReturnElement()) + return true; + + llvm::SmallVector DFSWorkList; + llvm::SmallPtrSet Visited; + + DFSWorkList.push_back(StartBlk); + while (!DFSWorkList.empty()) { + const CFGBlock *Blk = DFSWorkList.back(); + DFSWorkList.pop_back(); + Visited.insert(Blk); + + for (const auto &Succ : Blk->succs()) { + if (const CFGBlock *SuccBlk = Succ.getReachableBlock()) { + if (SuccBlk == &Cfg.getExit()) { + // We seem to be leaving the current CFG. + // We're no longer sure what happens next. + return false; + } + + if (!SuccBlk->hasNoReturnElement() && !Visited.count(SuccBlk)) { + // If the block has reachable child blocks that aren't no-return, + // add them to the worklist. + DFSWorkList.push_back(SuccBlk); + } + } + } + } + + // Nothing reached the exit. It can only mean one thing: there's no return. + return true; +} + static BugReport * FindReportInEquivalenceClass(BugReportEquivClass& EQ, SmallVectorImpl &bugReports) { @@ -3366,9 +3405,8 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, // We may be post-dominated in subsequent blocks, or even // inter-procedurally. However, it is not clear if more complicated // cases are generally worth suppressing. - if (const CFGBlock *B = findBlockForNode(errorNode)) - if (B->hasNoReturnElement()) - continue; + if (isDominatedByNoReturnBlocks(errorNode)) + 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. -- cgit v1.2.3