diff options
author | Anna Zaks <ganna@apple.com> | 2012-02-23 21:38:21 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-02-23 21:38:21 +0000 |
commit | ca8e36eb637e232475ef31c3f22d5da907390917 (patch) | |
tree | 1900fdf4f44573541cf80af124aef41c83cf8d27 /lib/StaticAnalyzer/Checkers/MallocChecker.cpp | |
parent | 55882446ce7b95f4b3993f1afe591cf0d06e4628 (diff) |
[analyzer] Malloc: unique leak reports by allocation site.
When we find two leak reports with the same allocation site, report only
one of them.
Provide a helper method to BugReporter to facilitate this.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151287 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 4ae1dd81ef..d6dc97a82c 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -186,6 +186,11 @@ private: static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const; + /// Find the location of the allocation for Sym on the path leading to the + /// exploded node N. + const Stmt *getAllocationSite(const ExplodedNode *N, SymbolRef Sym, + CheckerContext &C) const; + void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; /// The bug visitor which allows us to print extra diagnostics along the @@ -766,6 +771,24 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){ return MallocMemAux(C, CE, TotalSize, zeroVal, state); } +const Stmt * +MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, + CheckerContext &C) const { + // Walk the ExplodedGraph backwards and find the first node that referred to + // the tracked symbol. + const ExplodedNode *AllocNode = N; + + while (N) { + if (!N->getState()->get<RegionState>(Sym)) + break; + AllocNode = N; + N = N->pred_empty() ? NULL : *(N->pred_begin()); + } + + ProgramPoint P = AllocNode->getLocation(); + return cast<clang::PostStmt>(P).getStmt(); +} + void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const { assert(N); @@ -779,8 +802,16 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, BT_Leak->setSuppressOnSink(true); } + // Most bug reports are cached at the location where they occurred. + // With leaks, we want to unique them by the location where they were + // allocated, and only report a single path. + const Stmt *AllocStmt = getAllocationSite(N, Sym, C); + PathDiagnosticLocation LocUsedForUniqueing = + PathDiagnosticLocation::createBegin(AllocStmt, C.getSourceManager(), + N->getLocationContext()); + BugReport *R = new BugReport(*BT_Leak, - "Memory is never released; potential memory leak", N); + "Memory is never released; potential memory leak", N, LocUsedForUniqueing); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); } @@ -818,14 +849,17 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, } } - ExplodedNode *N = C.addTransition(state->set<RegionState>(RS)); + // Generate leak node. + static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak"); + ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); - if (N && generateReport) { + if (generateReport) { for (llvm::SmallVector<SymbolRef, 2>::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { reportLeak(*I, N, C); } } + C.addTransition(state->set<RegionState>(RS), N); } void MallocChecker::checkEndPath(CheckerContext &C) const { |