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.
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
{
ExplodedNode *N = C.addTransition(state->set<RegionState>(RS));
if (N && generateReport) {
- if (!BT_Leak)
- BT_Leak.reset(new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak."));
for (llvm::SmallVector<SymbolRef, 2>::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<RegionState>();
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);
}
}
}
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__));
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);