Implemented support for better localized leaks in the CF reference count checker.
Now leaks should be flagged close to where they occur.
This should implement the desired functionality in <rdar://problem/
5879592>, although the diagnostics still need to be improved.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50241
91177308-0d34-0410-b5e6-
96231b3b80d8
virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
- ProgramPoint P, ExplodedNode<ValueState>* Pred,
+ ExplodedNode<ValueState>* Pred,
+ Stmt* S,
ValueState* St,
const ValueStateManager::DeadSymbolsTy& Dead) {}
llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(G->Trim(&N, &N+1));
- // Find the sink node in the trimmed graph.
+ // Find the error node in the trimmed graph.
- N = NULL;
+ ExplodedNode<ValueState>* NOld = N;
+ N = 0;
for (ExplodedGraph<ValueState>::node_iterator
I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {
- if (I->isSink()) {
+ if (I->getState() == NOld->getState() &&
+ I->getLocation() == NOld->getLocation()) {
N = &*I;
break;
}
virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
- ProgramPoint P, ExplodedNode<ValueState>* Pred,
+ ExplodedNode<ValueState>* Pred,
+ Stmt* S,
ValueState* St,
const ValueStateManager::DeadSymbolsTy& Dead);
-
// Return statements.
virtual void EvalReturn(ExplodedNodeSet<ValueState>& Dst,
void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
- ProgramPoint P, ExplodedNode<ValueState>* Pred,
+ ExplodedNode<ValueState>* Pred,
+ Stmt* S,
ValueState* St,
const ValueStateManager::DeadSymbolsTy& Dead) {
-
- // FIXME: Have GRStmtNodeBuilder handle the case where 'P' is not PostStmt;
- // This won't result in missed leaks; we'll just flag these ones at the
- // end-of-path.
-
- Stmt* S = NULL;
-
- if (!isa<PostStmt>(P))
- return;
-
- S = cast<PostStmt>(P).getStmt();
-
+
// FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
RefBindings B = GetRefBindings(*St);
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
- TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode->getLocation(),
- EntryNode, CleanedState, DeadSymbols);
+ TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
+ CleanedState, DeadSymbols);
if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
Tmp.Add(EntryNode);
}
// Remove dead variable bindings.
+
+ DeadSymbols.clear();
+
for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I)
- if (!Marked.count(I.getKey()))
+ if (!Marked.count(I.getKey())) {
NewSt.VarBindings = Remove(NewSt, I.getKey());
+
+ RVal X = I.getData();
+
+ for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+ SI != SE; ++SI)
+ if (!MarkedSymbols.count(*SI)) DeadSymbols.insert(*SI);
+ }
// Remove dead symbols.
-
- DeadSymbols.clear();
-
+
for (ValueState::ce_iterator I = St->ce_begin(), E=St->ce_end(); I!=E; ++I) {
SymbolID sym = I.getKey();
return date; // expected-warning{{leak}}
}
+// Test a leak involving an overwrite.
+
+CFDateRef f7() {
+ CFDateRef date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+ CFRetain(date);
+ date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}}
+ return date;
+}