Newer
Older
// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
Ted Kremenek
committed
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the methods for CFRefCount, which implements
Ted Kremenek
committed
// a reference count checker for Core Foundation (Mac OS X).
//
//===----------------------------------------------------------------------===//
#include "GRSimpleVals.h"
#include "clang/Basic/LangOptions.h"
Ted Kremenek
committed
#include "clang/Analysis/PathSensitive/ValueState.h"
Ted Kremenek
committed
#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek
committed
#include "clang/Analysis/LocalCheckers.h"
Ted Kremenek
committed
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
Ted Kremenek
committed
#include "llvm/Support/Compiler.h"
Ted Kremenek
committed
#include <ostream>
Ted Kremenek
committed
using namespace clang;
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
//===----------------------------------------------------------------------===//
// Symbolic Evaluation of Reference Counting Logic
//===----------------------------------------------------------------------===//
namespace {
enum ArgEffect { IncRef, DecRef, DoNothing };
Ted Kremenek
committed
typedef std::vector<std::pair<unsigned,ArgEffect> > ArgEffects;
Ted Kremenek
committed
namespace llvm {
template <> struct FoldingSetTrait<ArgEffects> {
static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
Ted Kremenek
committed
for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) {
ID.AddInteger(I->first);
ID.AddInteger((unsigned) I->second);
}
};
} // end llvm namespace
namespace {
class RetEffect {
public:
Ted Kremenek
committed
enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
NotOwnedSymbol = 0x3 };
private:
unsigned Data;
RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; }
public:
Kind getKind() const { return (Kind) (Data & 0x3); }
unsigned getValue() const {
assert(getKind() == Alias);
return Data >> 2;
Ted Kremenek
committed
static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
Ted Kremenek
committed
static RetEffect MakeNoRet() { return RetEffect(NoRet, 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(); }
ArgEffect getArg(unsigned idx) const {
Ted Kremenek
committed
if (!Args)
return DoNothing;
// If Args is present, it is likely to contain only 1 element.
// Just do a linear search. Do it from the back because functions with
// large numbers of arguments will be tail heavy with respect to which
// argument they actually modify with respect to the reference count.
for (ArgEffects::reverse_iterator I=Args->rbegin(), E=Args->rend();
I!=E; ++I) {
if (idx > I->first)
return DoNothing;
if (idx == I->first)
return I->second;
}
return DoNothing;
RetEffect getRet() const {
return Ret;
}
typedef ArgEffects::const_iterator arg_iterator;
arg_iterator begin_args() const { return Args->begin(); }
arg_iterator end_args() const { return Args->end(); }
Ted Kremenek
committed
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);
}
};
Ted Kremenek
committed
class CFRefSummaryManager {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
ASTContext& Ctx;
const bool GCEnabled;
SummarySetTy SummarySet;
SummaryMapTy SummaryMap;
AESetTy AESet;
llvm::BumpPtrAllocator BPAlloc;
Ted Kremenek
committed
ArgEffects ScratchArgs;
ArgEffects* getArgEffects();
enum CFUnaryFunc { cfretain, cfrelease, cfmakecollectable };
CFRefSummary* getUnaryCFSummary(FunctionTypeProto* FT, CFUnaryFunc func);
CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
Ted Kremenek
committed
CFRefSummaryManager(ASTContext& ctx, bool gcenabled)
: Ctx(ctx), GCEnabled(gcenabled) {}
~CFRefSummaryManager();
Ted Kremenek
committed
CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Implementation of checker data structures.
//===----------------------------------------------------------------------===//
CFRefSummaryManager::~CFRefSummaryManager() {
Ted Kremenek
committed
// FIXME: The ArgEffects could eventually be allocated from BPAlloc,
// mitigating the need to do explicit cleanup of the
// Argument-Effect summaries.
Ted Kremenek
committed
for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
I->getValue().~ArgEffects();
Ted Kremenek
committed
}
ArgEffects* CFRefSummaryManager::getArgEffects() {
Ted Kremenek
committed
if (ScratchArgs.empty())
return NULL;
Loading
Loading full blame...