diff options
author | Ted Kremenek <kremenek@apple.com> | 2008-08-14 21:16:54 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2008-08-14 21:16:54 +0000 |
commit | 72cd17f0a4722e1fa3eb47c08a7aa29aeba16754 (patch) | |
tree | 70943c109a1aae572f700ece461d26a2b4fae6a9 /lib/Analysis/CFRefCount.cpp | |
parent | faf37e7d3646c4f473e7a565a9a2f8baed62dbe6 (diff) |
Migrated retain/release checker to use the Generic Data Map in GRState (instead
of using CheckerState).
Removed CheckerState from GRState.
Added class GRStateRef which wraps GRState* and GRStateManager*. This is handy
for generating new states with a single handle.
Added member template set/get functions to GRStateRef/GRState/GRStateManager for
accessing the Generic Data Map.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54788 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFRefCount.cpp')
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 267 |
1 files changed, 124 insertions, 143 deletions
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 256072ab3a..9a769988a1 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -1192,20 +1192,60 @@ void RefVal::print(std::ostream& Out) const { } } +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// RefBindings - State used to track object reference counts. +//===----------------------------------------------------------------------===// + +typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings; +typedef RefBindings::Factory RefBFactoryTy; + +static int RefBIndex = 0; + +namespace clang { +template<> struct GRStateTrait<RefBindings> { + typedef RefBindings data_type; + typedef RefBFactoryTy& context_type; + typedef SymbolID key_type; + typedef RefVal value_type; + typedef const RefVal* lookup_type; + + static RefBindings MakeData(void* const* p) { + return p ? RefBindings((RefBindings::TreeTy*) *p) : RefBindings(0); + } + static void* MakeVoidPtr(RefBindings B) { + return B.getRoot(); + } + static void* GDMIndex() { + return &RefBIndex; + } + static lookup_type Lookup(RefBindings B, SymbolID K) { + return B.lookup(K); + } + static data_type Set(RefBindings B, key_type K, value_type E, + RefBFactoryTy& F) { + return F.Add(B, K, E); + } + + static data_type Remove(RefBindings B, SymbolID K, RefBFactoryTy& F) { + return F.Remove(B, K); + } +}; +} + //===----------------------------------------------------------------------===// // Transfer functions. //===----------------------------------------------------------------------===// +namespace { + class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals { public: // Type definitions. - typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings; - - typedef RefBindings::Factory RefBFactoryTy; - typedef llvm::DenseMap<GRExprEngine::NodeTy*,std::pair<Expr*, SymbolID> > ReleasesNotOwnedTy; - + typedef ReleasesNotOwnedTy UseAfterReleasesTy; typedef llvm::DenseMap<GRExprEngine::NodeTy*, std::vector<SymbolID>*> @@ -1225,30 +1265,18 @@ private: ReleasesNotOwnedTy ReleasesNotOwned; LeaksTy Leaks; BindingsPrinter Printer; - -public: - - static RefBindings GetRefBindings(const GRState& StImpl) { - return RefBindings((const RefBindings::TreeTy*) StImpl.CheckerState); - } - - static RefBindings GetRefBindings(const GRState* state) { - return RefBindings((const RefBindings::TreeTy*) state->CheckerState); - } - -private: - - static void SetRefBindings(GRState& StImpl, RefBindings B) { - StImpl.CheckerState = B.getRoot(); - } - - RefBindings Remove(RefBindings B, SymbolID sym) { - return RefBFactory.Remove(B, sym); - } RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E, RefVal::Kind& hasErr); + RefVal::Kind& Update(GRStateRef& state, SymbolID sym, RefVal V, + ArgEffect E, RefVal::Kind& hasErr) { + + state = state.set<RefBindings>(Update(state.get<RefBindings>(), sym, V, + E, hasErr)); + return hasErr; + } + void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst, GRStmtNodeBuilder<GRState>& Builder, Expr* NodeExpr, Expr* ErrorExpr, @@ -1260,9 +1288,6 @@ private: const GRState* St, SymbolID sid, RefVal V, bool& hasLeak); - const GRState* NukeBinding(GRStateManager& VMgr, const GRState* St, - SymbolID sid); - public: CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts) @@ -1370,7 +1395,7 @@ public: void CFRefCount::BindingsPrinter::Print(std::ostream& Out, const GRState* state, const char* nl, const char* sep) { - RefBindings B = GetRefBindings(state); + RefBindings B = state->get<RefBindings>(); if (!B.isEmpty()) Out << sep << nl; @@ -1464,34 +1489,25 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, ExplodedNode<GRState>* Pred) { // Get the state. - GRStateManager& StateMgr = Eng.getStateManager(); - const GRState* St = Builder.GetState(Pred); + GRStateRef state(Builder.GetState(Pred), Eng.getStateManager()); // Evaluate the effect of the arguments. - GRState StVals = *St; RefVal::Kind hasErr = (RefVal::Kind) 0; unsigned idx = 0; Expr* ErrorExpr = NULL; SymbolID ErrorSym = 0; - for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { - - RVal V = StateMgr.GetRVal(St, *I); + for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { + RVal V = state.GetRVal(*I); if (isa<lval::SymbolVal>(V)) { SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol(); - RefBindings B = GetRefBindings(StVals); - - if (RefBindings::data_type* T = B.lookup(Sym)) { - B = Update(B, Sym, *T, GetArgE(Summ, idx), hasErr); - SetRefBindings(StVals, B); - - if (hasErr) { + if (RefBindings::data_type* T = state.get<RefBindings>(Sym)) + if (Update(state, Sym, *T, GetArgE(Summ, idx), hasErr)) { ErrorExpr = *I; ErrorSym = Sym; break; } - } } else if (isa<LVal>(V)) { #if 0 @@ -1515,58 +1531,48 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, // disambiguate conjured symbols. // Is the invalidated variable something that we were tracking? - RVal X = StateMgr.GetRVal(&StVals, *DV); + RVal X = state.GetRVal(*DV); if (isa<lval::SymbolVal>(X)) { SymbolID Sym = cast<lval::SymbolVal>(X).getSymbol(); - SetRefBindings(StVals,RefBFactory.Remove(GetRefBindings(StVals),Sym)); + state = state.remove<RefBindings>(Sym, RefBFactory); } // Set the value of the variable to be a conjured symbol. unsigned Count = Builder.getCurrentBlockCount(); SymbolID NewSym = Eng.getSymbolManager().getConjuredSymbol(*I, Count); - - StateMgr.SetRVal(StVals, *DV, - LVal::IsLValType(DV->getDecl()->getType()) - ? cast<RVal>(lval::SymbolVal(NewSym)) - : cast<RVal>(nonlval::SymbolVal(NewSym))); + + state = state.SetRVal(*DV, + LVal::IsLValType(DV->getDecl()->getType()) + ? cast<RVal>(lval::SymbolVal(NewSym)) + : cast<RVal>(nonlval::SymbolVal(NewSym))); } else { // Nuke all other arguments passed by reference. - StateMgr.Unbind(StVals, cast<LVal>(V)); + state = state.Unbind(cast<LVal>(V)); } #endif } else if (isa<nonlval::LValAsInteger>(V)) - StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal()); + state = state.Unbind(cast<nonlval::LValAsInteger>(V).getLVal()); } // Evaluate the effect on the message receiver. if (!ErrorExpr && Receiver) { - RVal V = StateMgr.GetRVal(St, Receiver); - + RVal V = state.GetRVal(Receiver); if (isa<lval::SymbolVal>(V)) { SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol(); - RefBindings B = GetRefBindings(StVals); - - if (const RefVal* T = B.lookup(Sym)) { - B = Update(B, Sym, *T, GetReceiverE(Summ), hasErr); - SetRefBindings(StVals, B); - - if (hasErr) { + if (const RefVal* T = state.get<RefBindings>(Sym)) + if (Update(state, Sym, *T, GetReceiverE(Summ), hasErr)) { ErrorExpr = Receiver; ErrorSym = Sym; } - } } } - - // Get the persistent state. - St = StateMgr.getPersistentState(StVals); // Process any errors. if (hasErr) { - ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, St, + ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state, hasErr, ErrorSym); return; } @@ -1592,7 +1598,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, ? cast<RVal>(lval::SymbolVal(Sym)) : cast<RVal>(nonlval::SymbolVal(Sym)); - St = StateMgr.SetRVal(St, Ex, X, Eng.getCFG().isBlkExpr(Ex), false); + state = state.SetRVal(Ex, X, Eng.getCFG().isBlkExpr(Ex), false); } break; @@ -1601,15 +1607,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, unsigned idx = RE.getIndex(); assert (arg_end >= arg_beg); assert (idx < (unsigned) (arg_end - arg_beg)); - RVal V = StateMgr.GetRVal(St, *(arg_beg+idx)); - St = StateMgr.SetRVal(St, Ex, V, Eng.getCFG().isBlkExpr(Ex), false); + RVal V = state.GetRVal(*(arg_beg+idx)); + state = state.SetRVal(Ex, V, Eng.getCFG().isBlkExpr(Ex), false); break; } case RetEffect::ReceiverAlias: { assert (Receiver); - RVal V = StateMgr.GetRVal(St, Receiver); - St = StateMgr.SetRVal(St, Ex, V, Eng.getCFG().isBlkExpr(Ex), false); + RVal V = state.GetRVal(Receiver); + state = state.SetRVal(Ex, V, Eng.getCFG().isBlkExpr(Ex), false); break; } @@ -1619,17 +1625,19 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count); QualType RetT = GetReturnType(Ex, Eng.getContext()); - GRState StImpl = *St; + state = state.set<RefBindings>(Sym, RefVal::makeOwned(RetT), RefBFactory); + state = state.SetRVal(Ex, lval::SymbolVal(Sym), + Eng.getCFG().isBlkExpr(Ex), false); + +#if 0 RefBindings B = GetRefBindings(StImpl); SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(RetT))); - - St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), - Ex, lval::SymbolVal(Sym), - Eng.getCFG().isBlkExpr(Ex), false); +#endif + // FIXME: Add a flag to the checker where allocations are allowed to fail. if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) - St = StateMgr.AddNE(St, Sym, Eng.getBasicVals().getZeroWithPtrWidth()); + state = state.AddNE(Sym, Eng.getBasicVals().getZeroWithPtrWidth()); break; } @@ -1639,24 +1647,18 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count); QualType RetT = GetReturnType(Ex, Eng.getContext()); - GRState StImpl = *St; - RefBindings B = GetRefBindings(StImpl); - SetRefBindings(StImpl, RefBFactory.Add(B, Sym, - RefVal::makeNotOwned(RetT))); - - St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), - Ex, lval::SymbolVal(Sym), + state = state.set<RefBindings>(Sym, RefVal::makeNotOwned(RetT), RefBFactory); + state = state.SetRVal(Ex, lval::SymbolVal(Sym), Eng.getCFG().isBlkExpr(Ex), false); - break; } } // Is this a sink? if (IsEndPath(Summ)) - Builder.MakeSinkNode(Dst, Ex, Pred, St); + Builder.MakeSinkNode(Dst, Ex, Pred, state); else - Builder.MakeNode(Dst, Ex, Pred, St); + Builder.MakeNode(Dst, Ex, Pred, state); } @@ -1693,7 +1695,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, if (isa<lval::SymbolVal>(V)) { SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol(); - if (const RefVal* T = GetRefBindings(*St).lookup(Sym)) { + if (const RefVal* T = St->get<RefBindings>(Sym)) { QualType Ty = T->getType(); if (const PointerType* PT = Ty->getAsPointerType()) { @@ -1743,24 +1745,16 @@ void CFRefCount::EvalStore(ExplodedNodeSet<GRState>& Dst, SymbolID Sym = cast<lval::SymbolVal>(Val).getSymbol(); - if (!GetRefBindings(*St).lookup(Sym)) - return; + GRStateRef state(St, Eng.getStateManager()); - // Nuke the binding. - St = NukeBinding(Eng.getStateManager(), St, Sym); + if (!state.get<RefBindings>(Sym)) + return; - // Hand of the remaining logic to the parent implementation. - GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, St, TargetLV, Val); -} + // Nuke the binding. + state = state.remove<RefBindings>(Sym, RefBFactory); - -const GRState* CFRefCount::NukeBinding(GRStateManager& VMgr, - const GRState* St, - SymbolID sid) { - GRState StImpl = *St; - RefBindings B = GetRefBindings(StImpl); - StImpl.CheckerState = RefBFactory.Remove(B, sid).getRoot(); - return VMgr.getPersistentState(StImpl); + // Hand of the remaining logic to the parent implementation. + GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, state, TargetLV, Val); } // End-of-path. @@ -1772,21 +1766,19 @@ const GRState* CFRefCount::HandleSymbolDeath(GRStateManager& VMgr, hasLeak = V.isOwned() || ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); + GRStateRef state(St, VMgr); + if (!hasLeak) - return NukeBinding(VMgr, St, sid); - - RefBindings B = GetRefBindings(*St); - GRState StImpl = *St; - StImpl.CheckerState = RefBFactory.Add(B, sid, V^RefVal::ErrorLeak).getRoot(); + return state.remove<RefBindings>(sid, RefBFactory); - return VMgr.getPersistentState(StImpl); + return state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak, RefBFactory); } void CFRefCount::EvalEndPath(GRExprEngine& Eng, GREndPathNodeBuilder<GRState>& Builder) { const GRState* St = Builder.getState(); - RefBindings B = GetRefBindings(*St); + RefBindings B = St->get<RefBindings>(); llvm::SmallVector<SymbolID, 10> Leaked; @@ -1828,7 +1820,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst, // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor. - RefBindings B = GetRefBindings(*St); + RefBindings B = St->get<RefBindings>(); llvm::SmallVector<SymbolID, 10> Leaked; for (GRStateManager::DeadSymbolsTy::const_iterator @@ -1875,27 +1867,23 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst, Expr* RetE = S->getRetValue(); if (!RetE) return; - GRStateManager& StateMgr = Eng.getStateManager(); - const GRState* St = Builder.GetState(Pred); - RVal V = StateMgr.GetRVal(St, RetE); + GRStateRef state(Builder.GetState(Pred), Eng.getStateManager()); + RVal V = state.GetRVal(RetE); if (!isa<lval::SymbolVal>(V)) return; // Get the reference count binding (if any). SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol(); - RefBindings B = GetRefBindings(*St); - const RefVal* T = B.lookup(Sym); + const RefVal* T = state.get<RefBindings>(Sym); if (!T) return; - // Change the reference count. - + // Change the reference count. RefVal X = *T; - switch (X.getKind()) { - + switch (X.getKind()) { case RefVal::Owned: { unsigned cnt = X.getCount(); assert (cnt > 0); @@ -1915,10 +1903,8 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst, } // Update the binding. - - GRState StImpl = *St; - StImpl.CheckerState = RefBFactory.Add(B, Sym, X).getRoot(); - Builder.MakeNode(Dst, S, Pred, StateMgr.getPersistentState(StImpl)); + state = state.set<RefBindings>(Sym, X, RefBFactory); + Builder.MakeNode(Dst, S, Pred, state); } // Assumptions. @@ -1934,7 +1920,7 @@ const GRState* CFRefCount::EvalAssume(GRStateManager& VMgr, // too bad since the number of symbols we will track in practice are // probably small and EvalAssume is only called at branches and a few // other places. - RefBindings B = GetRefBindings(*St); + RefBindings B = St->get<RefBindings>(); if (B.isEmpty()) return St; @@ -1953,14 +1939,14 @@ const GRState* CFRefCount::EvalAssume(GRStateManager& VMgr, if (!changed) return St; - GRState StImpl = *St; - StImpl.CheckerState = B.getRoot(); - return VMgr.getPersistentState(StImpl); + GRStateRef state(St, VMgr); + state = state.set<RefBindings>(B); + return state; } -CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym, - RefVal V, ArgEffect E, - RefVal::Kind& hasErr) { +RefBindings CFRefCount::Update(RefBindings B, SymbolID sym, + RefVal V, ArgEffect E, + RefVal::Kind& hasErr) { // FIXME: This dispatch can potentially be sped up by unifiying it into // a single switch statement. Opt for simplicity for now. @@ -2215,8 +2201,8 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<GRState>* N, const GRState* PrevSt = PrevN->getState(); const GRState* CurrSt = N->getState(); - CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt); - CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt); + RefBindings PrevB = PrevSt->get<RefBindings>(); + RefBindings CurrB = CurrSt->get<RefBindings>(); const RefVal* PrevT = PrevB.lookup(Sym); const RefVal* CurrT = CurrB.lookup(Sym); @@ -2273,6 +2259,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<GRState>* N, // The typestate has changed. std::ostringstream os; + std::string s; switch (CurrV.getKind()) { case RefVal::Owned: @@ -2296,7 +2283,8 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<GRState>* N, os << " retain count."; } - Msg = os.str().c_str(); + s = os.str(); + Msg = s.c_str(); break; @@ -2342,7 +2330,6 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<GRState>* N, static std::pair<ExplodedNode<GRState>*,VarDecl*> GetAllocationSite(ExplodedNode<GRState>* N, SymbolID Sym) { - typedef CFRefCount::RefBindings RefBindings; ExplodedNode<GRState>* Last = N; // Find the first node that referred to the tracked symbol. We also @@ -2352,7 +2339,7 @@ GetAllocationSite(ExplodedNode<GRState>* N, SymbolID Sym) { while (N) { const GRState* St = N->getState(); - RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState); + RefBindings B = St->get<RefBindings>(); if (!B.lookup(Sym)) break; @@ -2392,17 +2379,12 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR, if (!getBugType().isLeak()) return RangedBugReport::getEndPath(BR, EndN); - typedef CFRefCount::RefBindings RefBindings; - // Get the retain count. - - unsigned long RetCount = - CFRefCount::GetRefBindings(*EndN->getState()).lookup(Sym)->getCount(); + unsigned long RetCount = EndN->getState()->get<RefBindings>(Sym)->getCount(); // We are a leak. Walk up the graph to get to the first node where the // symbol appeared, and also get the first VarDecl that tracked object // is stored to. - ExplodedNode<GRState>* AllocNode = 0; VarDecl* FirstDecl = 0; llvm::tie(AllocNode, FirstDecl) = GetAllocationSite(EndN, Sym); @@ -2434,7 +2416,6 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR, // Look in the *trimmed* graph at the immediate predecessor of EndN. Does // it occur on the same line? - PathDiagnosticPiece::DisplayHint Hint = PathDiagnosticPiece::Above; assert (!EndN->pred_empty()); // Not possible to have 0 predecessors. |