2008-03-06 00:08:09 +00:00
|
|
|
// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-03-06 10:40:09 +00:00
|
|
|
// This file defines the methods for CFRefCount, which implements
|
2008-03-06 00:08:09 +00:00
|
|
|
// a reference count checker for Core Foundation (Mac OS X).
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
#include "GRSimpleVals.h"
|
2008-03-06 00:08:09 +00:00
|
|
|
#include "clang/Analysis/PathSensitive/ValueState.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "clang/Analysis/LocalCheckers.h"
|
2008-03-11 06:39:11 +00:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
|
|
#include "llvm/ADT/ImmutableMap.h"
|
2008-03-06 00:08:09 +00:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
namespace {
|
|
|
|
enum ArgEffect { IncRef, DecRef, DoNothing };
|
|
|
|
typedef std::vector<ArgEffect> ArgEffects;
|
|
|
|
}
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
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 {
|
|
|
|
|
|
|
|
class RetEffect {
|
|
|
|
public:
|
|
|
|
enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
|
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned Data;
|
|
|
|
RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Kind getKind() const { return (Kind) (Data & 0x3); }
|
|
|
|
|
|
|
|
unsigned getValue() const {
|
|
|
|
assert(getKind() == Alias);
|
|
|
|
return Data & ~0x3;
|
|
|
|
}
|
|
|
|
|
|
|
|
static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
|
|
|
|
|
|
|
|
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(); }
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
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();
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
CFRefSummary* getSummary(FunctionDecl* FD);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Implementation of checker data structures.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
CFRefSummaryManager::~CFRefSummaryManager() {
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
// FIXME: The ArgEffects could eventually be allocated from BPAlloc,
|
|
|
|
// mitigating the need to do explicit cleanup of the
|
|
|
|
// Argument-Effect summaries.
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
|
|
|
|
I->getValue().~ArgEffects();
|
2008-03-06 00:08:09 +00:00
|
|
|
}
|
2008-03-11 06:39:11 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
return NULL;
|
2008-03-06 00:08:09 +00:00
|
|
|
}
|
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// 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
|
|
|
|
|
2008-03-06 00:08:09 +00:00
|
|
|
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
|
|
|
|
ValueStateManager& StateMgr,
|
|
|
|
GRStmtNodeBuilder<ValueState>& Builder,
|
2008-03-07 20:13:31 +00:00
|
|
|
BasicValueFactory& BasicVals,
|
2008-03-06 00:08:09 +00:00
|
|
|
CallExpr* CE, LVal L,
|
|
|
|
ExplodedNode<ValueState>* Pred) {
|
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
// Get the summary.
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
lval::FuncVal FV = cast<lval::FuncVal>(L);
|
|
|
|
FunctionDecl* FD = FV.getDecl();
|
|
|
|
CFRefSummary* Summ = Summaries.getSummary(FD);
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
// Get the state.
|
|
|
|
|
|
|
|
ValueState* St = Builder.GetState(Pred);
|
|
|
|
|
|
|
|
// Evaluate the effects of the call.
|
|
|
|
|
|
|
|
ValueState StVals = *St;
|
|
|
|
|
|
|
|
if (!Summ) {
|
|
|
|
|
|
|
|
// 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;
|
2008-03-06 00:08:09 +00:00
|
|
|
|
2008-03-11 06:39:11 +00:00
|
|
|
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));
|
|
|
|
}
|
2008-03-06 00:08:09 +00:00
|
|
|
}
|
2008-03-11 06:39:11 +00:00
|
|
|
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);
|
2008-03-06 00:08:09 +00:00
|
|
|
|
|
|
|
Builder.Nodify(Dst, CE, Pred, St);
|
|
|
|
}
|
2008-03-11 06:39:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
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
|