From da04677092c7b08fe7438f82a8636dcc8c6e9683 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Sat, 11 Feb 2012 21:02:40 +0000 Subject: [PATCH] [analyzer] Malloc checker: Leak bugs should be suppressed by sinks. Resolves a common false positive, where we were reporting a leak inside asserts git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150312 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 46 +++++++++++-------- test/Analysis/malloc.c | 14 ++---- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 430a77a570..d858959bd5 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -148,6 +148,8 @@ private: static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const; + void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; + /// The bug visitor which allows us to print extra diagnostics along the /// BugReport path. For example, showing the allocation site of the leaked /// region. @@ -672,6 +674,25 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) { C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state)); } +void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, + CheckerContext &C) const { + assert(N); + if (!BT_Leak) { + BT_Leak.reset(new BuiltinBug("Memory leak", + "Allocated memory never released. Potential memory leak.")); + // Leaks should not be reported if they are post-dominated by a sink: + // (1) Sinks are higher importance bugs. + // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending + // with __noreturn functions such as assert() or exit(). We choose not + // to report leaks on such paths. + BT_Leak->setSuppressOnSink(true); + } + + BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); + R->addVisitor(new MallocBugVisitor(Sym)); + C.EmitReport(R); +} + void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { @@ -699,34 +720,23 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, ExplodedNode *N = C.addTransition(state->set(RS)); if (N && generateReport) { - if (!BT_Leak) - BT_Leak.reset(new BuiltinBug("Memory leak", - "Allocated memory never released. Potential memory leak.")); for (llvm::SmallVector::iterator - I = Errors.begin(), E = Errors.end(); I != E; ++I) { - BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); - R->addVisitor(new MallocBugVisitor(*I)); - C.EmitReport(R); + I = Errors.begin(), E = Errors.end(); I != E; ++I) { + reportLeak(*I, N, C); } } } -void MallocChecker::checkEndPath(CheckerContext &Ctx) const { - ProgramStateRef state = Ctx.getState(); +void MallocChecker::checkEndPath(CheckerContext &C) const { + ProgramStateRef state = C.getState(); RegionStateTy M = state->get(); for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) { RefState RS = I->second; if (RS.isAllocated()) { - ExplodedNode *N = Ctx.addTransition(state); - if (N) { - if (!BT_Leak) - BT_Leak.reset(new BuiltinBug("Memory leak", - "Allocated memory never released. Potential memory leak.")); - BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); - R->addVisitor(new MallocBugVisitor(I->first)); - Ctx.EmitReport(R); - } + ExplodedNode *N = C.addTransition(state); + if (N) + reportLeak(I->first, N, C); } } } diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index a219e92787..89299e6637 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -340,21 +340,15 @@ int **RegInvalidationDetect2(int **pp) { return 0;// expected-warning {{Allocated memory never released. Potential memory leak.}} } -// Below are the known false positives. - extern void exit(int) __attribute__ ((__noreturn__)); void mallocExit(int *g) { struct xx *p = malloc(12); - - if (g != 0) { - exit(1); // expected-warning{{Allocated memory never released. Potential memory leak}} - } + if (g != 0) + exit(1); free(p); return; } - -// TODO: There should be no warning here. extern void __assert_fail (__const char *__assertion, __const char *__file, unsigned int __line, __const char *__function) __attribute__ ((__noreturn__)); @@ -363,11 +357,13 @@ extern void __assert_fail (__const char *__assertion, __const char *__file, void mallocAssert(int *g) { struct xx *p = malloc(12); - assert(g != 0); // expected-warning{{Allocated memory never released. Potential memory leak}} + assert(g != 0); free(p); return; } +// Below are the known false positives. + // TODO: There should be no warning here. void reallocFails(int *g, int f) { char *p = malloc(12); -- 2.50.1