forked from OSchip/llvm-project
Added main skeleton for CFRetain transfer function logic.
llvm-svn: 48214
This commit is contained in:
parent
5c7bda440f
commit
819e9b6f39
|
@ -12,35 +12,188 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CFRefCount.h"
|
||||
#include "GRSimpleVals.h"
|
||||
#include "clang/Analysis/PathSensitive/ValueState.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
enum ArgEffect { IncRef, DecRef, DoNothing };
|
||||
typedef std::vector<ArgEffect> ArgEffects;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
namespace llvm {
|
||||
template <> struct FoldingSetTrait<ArgEffects> {
|
||||
static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
|
||||
for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
|
||||
ID.AddInteger((unsigned) *I);
|
||||
}
|
||||
|
||||
static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
|
||||
Profile(X, ID);
|
||||
}
|
||||
};
|
||||
} // end llvm namespace
|
||||
|
||||
namespace {
|
||||
|
||||
void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
Diagnostic& Diag) {
|
||||
class RetEffect {
|
||||
public:
|
||||
enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
|
||||
|
||||
private:
|
||||
unsigned Data;
|
||||
RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
|
||||
|
||||
if (Diag.hasErrorOccurred())
|
||||
return;
|
||||
public:
|
||||
|
||||
Kind getKind() const { return (Kind) (Data & 0x3); }
|
||||
|
||||
unsigned getValue() const {
|
||||
assert(getKind() == Alias);
|
||||
return Data & ~0x3;
|
||||
}
|
||||
|
||||
// FIXME: Refactor some day so this becomes a single function invocation.
|
||||
static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
|
||||
|
||||
GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
|
||||
GRExprEngine* CS = &Engine.getCheckerState();
|
||||
CFRefCount TF;
|
||||
CS->setTransferFunctions(TF);
|
||||
Engine.ExecuteWorkList(20000);
|
||||
static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
|
||||
|
||||
static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
|
||||
|
||||
operator Kind() const { return getKind(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
|
||||
};
|
||||
|
||||
|
||||
class CFRefSummary : public llvm::FoldingSetNode {
|
||||
ArgEffects* Args;
|
||||
RetEffect Ret;
|
||||
public:
|
||||
|
||||
CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
|
||||
|
||||
unsigned getNumArgs() const { return Args->size(); }
|
||||
|
||||
typedef ArgEffects::const_iterator arg_iterator;
|
||||
|
||||
arg_iterator begin_args() const { return Args->begin(); }
|
||||
arg_iterator end_args() const { return Args->end(); }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
|
||||
ID.AddPointer(A);
|
||||
ID.Add(R);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, Args, Ret);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CFRefSummaryManager {
|
||||
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
|
||||
typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
|
||||
typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
|
||||
|
||||
SummarySetTy SummarySet;
|
||||
SummaryMapTy SummaryMap;
|
||||
AESetTy AESet;
|
||||
llvm::BumpPtrAllocator BPAlloc;
|
||||
|
||||
ArgEffects ScratchArgs;
|
||||
|
||||
public:
|
||||
CFRefSummaryManager() {}
|
||||
~CFRefSummaryManager();
|
||||
|
||||
CFRefSummary* getSummary(FunctionDecl* FD);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation of checker data structures.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CFRefSummaryManager::~CFRefSummaryManager() {
|
||||
|
||||
// FIXME: The ArgEffects could eventually be allocated from BPAlloc,
|
||||
// mitigating the need to do explicit cleanup of the
|
||||
// Argument-Effect summaries.
|
||||
|
||||
for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
|
||||
I->getValue().~ArgEffects();
|
||||
}
|
||||
|
||||
CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
|
||||
|
||||
{ // Look into our cache of summaries to see if we have already computed
|
||||
// a summary for this FunctionDecl.
|
||||
|
||||
SummaryMapTy::iterator I = SummaryMap.find(FD);
|
||||
|
||||
if (I != SummaryMap.end())
|
||||
return I->second;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef unsigned RefState; // FIXME
|
||||
|
||||
namespace {
|
||||
|
||||
class CFRefCount : public GRSimpleVals {
|
||||
typedef llvm::ImmutableMap<SymbolID, RefState> RefBindings;
|
||||
typedef RefBindings::Factory RefBFactoryTy;
|
||||
|
||||
CFRefSummaryManager Summaries;
|
||||
RefBFactoryTy RefBFactory;
|
||||
|
||||
static RefBindings GetRefBindings(ValueState& StImpl) {
|
||||
return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
|
||||
}
|
||||
|
||||
static void SetRefBindings(ValueState& StImpl, RefBindings B) {
|
||||
StImpl.CheckerState = B.getRoot();
|
||||
}
|
||||
|
||||
RefBindings Remove(RefBindings B, SymbolID sym) {
|
||||
return RefBFactory.Remove(B, sym);
|
||||
}
|
||||
|
||||
RefBindings Update(RefBindings B, SymbolID sym,
|
||||
CFRefSummary* Summ, unsigned ArgIdx);
|
||||
|
||||
public:
|
||||
CFRefCount() {}
|
||||
virtual ~CFRefCount() {}
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
|
@ -48,18 +201,104 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
|||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred) {
|
||||
|
||||
ValueState* St = Pred->getState();
|
||||
// FIXME: Support calls to things other than lval::FuncVal. At the very
|
||||
// least we should stop tracking ref-state for ref-counted objects passed
|
||||
// to these functions.
|
||||
|
||||
// Invalidate all arguments passed in by reference (LVals).
|
||||
assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
|
||||
|
||||
// Get the summary.
|
||||
|
||||
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
|
||||
I != E; ++I) {
|
||||
lval::FuncVal FV = cast<lval::FuncVal>(L);
|
||||
FunctionDecl* FD = FV.getDecl();
|
||||
CFRefSummary* Summ = Summaries.getSummary(FD);
|
||||
|
||||
RVal V = StateMgr.GetRVal(St, *I);
|
||||
// Get the state.
|
||||
|
||||
ValueState* St = Builder.GetState(Pred);
|
||||
|
||||
// Evaluate the effects of the call.
|
||||
|
||||
ValueState StVals = *St;
|
||||
|
||||
if (!Summ) {
|
||||
|
||||
if (isa<LVal>(V))
|
||||
St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
|
||||
// This function has no summary. Invalidate all reference-count state
|
||||
// for arguments passed to this function, and also nuke the values of
|
||||
// arguments passed-by-reference.
|
||||
|
||||
ValueState StVals = *St;
|
||||
|
||||
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
|
||||
I != E; ++I) {
|
||||
|
||||
RVal V = StateMgr.GetRVal(St, *I);
|
||||
|
||||
if (isa<lval::SymbolVal>(V)) {
|
||||
SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
|
||||
RefBindings B = GetRefBindings(StVals);
|
||||
SetRefBindings(StVals, Remove(B, Sym));
|
||||
}
|
||||
|
||||
if (isa<LVal>(V))
|
||||
StateMgr.Unbind(StVals, cast<LVal>(V));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// This function has a summary. Evaluate the effect of the arguments.
|
||||
|
||||
unsigned idx = 0;
|
||||
|
||||
for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
|
||||
I!=E; ++I, ++idx) {
|
||||
|
||||
RVal V = StateMgr.GetRVal(St, *I);
|
||||
|
||||
if (isa<lval::SymbolVal>(V)) {
|
||||
SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
|
||||
RefBindings B = GetRefBindings(StVals);
|
||||
SetRefBindings(StVals, Update(B, Sym, Summ, idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
St = StateMgr.getPersistentState(StVals);
|
||||
|
||||
Builder.Nodify(Dst, CE, Pred, St);
|
||||
}
|
||||
|
||||
|
||||
CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
|
||||
CFRefSummary* Summ, unsigned ArgIdx){
|
||||
|
||||
assert (Summ);
|
||||
|
||||
// FIXME: Implement.
|
||||
|
||||
return B;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Driver for the CFRefCount Checker.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
|
||||
void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
Diagnostic& Diag) {
|
||||
|
||||
if (Diag.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
// FIXME: Refactor some day so this becomes a single function invocation.
|
||||
|
||||
GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
|
||||
GRExprEngine* CS = &Engine.getCheckerState();
|
||||
CFRefCount TF;
|
||||
CS->setTransferFunctions(TF);
|
||||
Engine.ExecuteWorkList(20000);
|
||||
|
||||
}
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
// CFRefCount.h - Transfer functions for the CF Ref. Count checker -*- C++ -*---
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines CFRefCount, which defines the transfer functions
|
||||
// to implement the Core Foundation reference count checker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRREFCOUNT
|
||||
#define LLVM_CLANG_ANALYSIS_GRREFCOUNT
|
||||
|
||||
#include "GRSimpleVals.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CFRefCount : public GRSimpleVals {
|
||||
public:
|
||||
CFRefCount() {}
|
||||
virtual ~CFRefCount() {}
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
||||
ValueStateManager& StateMgr,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
BasicValueFactory& BasicVals,
|
||||
CallExpr* CE, LVal L,
|
||||
ExplodedNode<ValueState>* Pred);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
|
@ -442,6 +442,14 @@ ValueState* ValueStateManager::UnbindVar(ValueState* St, VarDecl* D) {
|
|||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
void ValueStateManager::Unbind(ValueState& StImpl, LVal LV) {
|
||||
|
||||
if (isa<lval::DeclVal>(LV))
|
||||
StImpl.VarBindings = VBFactory.Remove(StImpl.VarBindings,
|
||||
cast<lval::DeclVal>(LV).getDecl());
|
||||
|
||||
}
|
||||
|
||||
ValueState* ValueStateManager::getInitialState() {
|
||||
|
||||
// Create a state with empty variable bindings.
|
||||
|
|
|
@ -234,6 +234,9 @@ public:
|
|||
RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
|
||||
|
||||
void BindVar(ValueState& StImpl, VarDecl* D, RVal V);
|
||||
|
||||
void Unbind(ValueState& StImpl, LVal LV);
|
||||
|
||||
ValueState* getPersistentState(ValueState& Impl);
|
||||
|
||||
ValueState* AddEQ(ValueState* St, SymbolID sym, const llvm::APSInt& V);
|
||||
|
|
Loading…
Reference in New Issue