aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Analysis/ProgramPoint.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp49
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp21
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp13
4 files changed, 65 insertions, 20 deletions
diff --git a/lib/Analysis/ProgramPoint.cpp b/lib/Analysis/ProgramPoint.cpp
index 3a0bbd5640..3f711b447a 100644
--- a/lib/Analysis/ProgramPoint.cpp
+++ b/lib/Analysis/ProgramPoint.cpp
@@ -34,8 +34,6 @@ ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
return PostLoad(S, LC, tag);
case ProgramPoint::PreStoreKind:
return PreStore(S, LC, tag);
- case ProgramPoint::PostStoreKind:
- return PostStore(S, LC, tag);
case ProgramPoint::PostLValueKind:
return PostLValue(S, LC, tag);
case ProgramPoint::PostPurgeDeadSymbolsKind:
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 99b84897a5..84366f434b 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -82,6 +82,8 @@ struct ReallocPair {
}
};
+typedef std::pair<const Stmt*, const MemRegion*> LeakInfo;
+
class MallocChecker : public Checker<check::DeadSymbols,
check::EndPath,
check::PreStmt<ReturnStmt>,
@@ -185,8 +187,8 @@ private:
/// 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;
+ LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const;
void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
@@ -797,17 +799,32 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){
return MallocMemAux(C, CE, TotalSize, zeroVal, state);
}
-const Stmt *
+LeakInfo
MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
CheckerContext &C) const {
const LocationContext *LeakContext = N->getLocationContext();
// Walk the ExplodedGraph backwards and find the first node that referred to
// the tracked symbol.
const ExplodedNode *AllocNode = N;
+ const MemRegion *ReferenceRegion = 0;
while (N) {
- if (!N->getState()->get<RegionState>(Sym))
+ ProgramStateRef State = N->getState();
+ if (!State->get<RegionState>(Sym))
break;
+
+ // Find the most recent expression bound to the symbol in the current
+ // context.
+ ProgramPoint L = N->getLocation();
+ if (!ReferenceRegion) {
+ const MemRegion *MR = C.getLocationRegionIfPostStore(N);
+ if (MR) {
+ SVal Val = State->getSVal(MR);
+ if (Val.getAsLocSymbol() == Sym)
+ ReferenceRegion = MR;
+ }
+ }
+
// Allocation node, is the last node in the current context in which the
// symbol was tracked.
if (N->getLocationContext() == LeakContext)
@@ -816,10 +833,11 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
}
ProgramPoint P = AllocNode->getLocation();
- if (!isa<StmtPoint>(P))
- return 0;
+ const Stmt *AllocationStmt = 0;
+ if (isa<StmtPoint>(P))
+ AllocationStmt = cast<StmtPoint>(P).getStmt();
- return cast<StmtPoint>(P).getStmt();
+ return LeakInfo(AllocationStmt, ReferenceRegion);
}
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
@@ -839,12 +857,23 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- if (const Stmt *AllocStmt = getAllocationSite(N, Sym, C))
+ const Stmt *AllocStmt = 0;
+ const MemRegion *Region = 0;
+ llvm::tie(AllocStmt, Region) = getAllocationSite(N, Sym, C);
+ if (AllocStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
C.getSourceManager(), N->getLocationContext());
- BugReport *R = new BugReport(*BT_Leak,
- "Memory is never released; potential memory leak", N, LocUsedForUniqueing);
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << "Memory is never released; potential leak";
+ if (Region) {
+ os << " of memory pointed to by '";
+ Region->dumpPretty(os);
+ os <<'\'';
+ }
+
+ BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
R->markInteresting(Sym);
// FIXME: This is a hack to make sure the MallocBugVisitor gets to look at
// the ExplodedNode chain first, in order to mark any failed realloc symbols
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index fa52beea2a..a1be56426e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1454,21 +1454,22 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit,
- ProgramPoint::Kind PointKind) {
+ SVal location, SVal Val, bool atDeclInit) {
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
- StoreE, *this, PointKind);
+ StoreE, *this,
+ ProgramPoint::PostStmtKind);
- // TODO:AZ Remove TmpDst after NB refactoring is done.
ExplodedNodeSet TmpDst;
StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext);
+ const LocationContext *LC = Pred->getLocationContext();
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
- ProgramStateRef state = (*I)->getState();
+ ExplodedNode *PredI = *I;
+ ProgramStateRef state = PredI->getState();
if (atDeclInit) {
const VarRegion *VR =
@@ -1479,7 +1480,12 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
state = state->bindLoc(location, Val);
}
- Bldr.generateNode(StoreE, *I, state, false, 0, PointKind);
+ const MemRegion *LocReg = 0;
+ if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location))
+ LocReg = LocRegVal->getRegion();
+
+ const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
+ Bldr.generateNode(L, PredI, state, false);
}
Dst.insert(TmpDst);
@@ -1517,8 +1523,7 @@ void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
return;
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- evalBind(Dst, StoreE, *NI, location, Val, false,
- ProgramPoint::PostStoreKind);
+ evalBind(Dst, StoreE, *NI, location, Val, false);
}
void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex,
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 501fd41cdf..ed94c79df1 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -534,6 +534,19 @@ void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "GlobalImmutableSpaceRegion";
}
+void MemRegion::dumpPretty(raw_ostream &os) const {
+ return;
+}
+
+void VarRegion::dumpPretty(raw_ostream &os) const {
+ os << getDecl()->getName();
+}
+
+void FieldRegion::dumpPretty(raw_ostream &os) const {
+ superRegion->dumpPretty(os);
+ os << "->" << getDecl();
+}
+
//===----------------------------------------------------------------------===//
// MemRegionManager methods.
//===----------------------------------------------------------------------===//