Newer
Older
//=-- GRExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
// is built on GREngine, but provides the boilerplate to execute transfer
// functions and build the ExplodedGraph at the expression level.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenek
committed
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/PathSensitive/BasicStore.h"
Ted Kremenek
committed
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#include <sstream>
#endif
using namespace clang;
using llvm::dyn_cast;
using llvm::cast;
using llvm::APSInt;
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
Ted Kremenek
committed
GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx,
LiveVariables& L)
: CoreEngine(cfg, CD, Ctx, *this),
G(CoreEngine.getGraph()),
Ted Kremenek
committed
Liveness(L),
Builder(NULL),
StateMgr(G.getContext(), CreateBasicStoreManager(G.getAllocator()),
G.getAllocator()),
BasicVals(StateMgr.getBasicValueFactory()),
TF(NULL), // FIXME
SymMgr(StateMgr.getSymbolManager()),
Ted Kremenek
committed
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
Ted Kremenek
committed
RaiseSel(GetNullarySelector("raise", G.getContext())) {}
for (BugTypeSet::iterator I = BugTypes.begin(), E = BugTypes.end(); I!=E; ++I)
delete *I;
for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
I != E; ++I)
delete *I;
for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
I != E; ++I)
delete *I;
Ted Kremenek
committed
delete [] NSExceptionInstanceRaiseSelectors;
}
//===----------------------------------------------------------------------===//
// Utility methods.
//===----------------------------------------------------------------------===//
// SaveAndRestore - A utility class that uses RIIA to save and restore
// the value of a variable.
template<typename T>
struct VISIBILITY_HIDDEN SaveAndRestore {
SaveAndRestore(T& x) : X(x), old_value(x) {}
~SaveAndRestore() { X = old_value; }
T get() { return old_value; }
T& X;
T old_value;
};
// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
// value of a variable is saved, and during the dstor the old value is
// or'ed with the new value.
struct VISIBILITY_HIDDEN SaveOr {
SaveOr(bool& x) : X(x), old_value(x) { x = false; }
~SaveOr() { X |= old_value; }
bool& X;
bool old_value;
};
void GRExprEngine::EmitWarnings(BugReporterData& BRData) {
for (bug_type_iterator I = bug_types_begin(), E = bug_types_end(); I!=E; ++I){
GRBugReporter BR(BRData, *this);
(*I)->EmitWarnings(BR);
}
for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
I != E; ++I) {
GRBugReporter BR(BRData, *this);
(*I)->EmitWarnings(BR);
}
for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
I != E; ++I) {
GRBugReporter BR(BRData, *this);
(*I)->EmitWarnings(BR);
}
}
void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
TF = tf;
TF->RegisterChecks(*this);
}
void GRExprEngine::AddCallCheck(GRSimpleAPICheck* A) {
CallChecks.push_back(A);
}
void GRExprEngine::AddObjCMessageExprCheck(GRSimpleAPICheck* A) {
MsgExprChecks.push_back(A);
}
const ValueState* GRExprEngine::getInitialState() {
// The LiveVariables information already has a compilation of all VarDecls
// used in the function. Iterate through this set, and "symbolicate"
// any VarDecl whose value originally comes from outside the function.
typedef LiveVariables::AnalysisDataTy LVDataTy;
LVDataTy& D = Liveness.getAnalysisData();
ValueState StateImpl = *StateMgr.getInitialState();
for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
Chris Lattner
committed
ScopedDecl *SD = const_cast<ScopedDecl*>(I->first);
if (VarDecl* VD = dyn_cast<VarDecl>(SD)) {
if (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD)) {
RVal X = RVal::GetSymbolValue(SymMgr, VD);
StateMgr.SetRVal(StateImpl, lval::DeclVal(VD), X);
Chris Lattner
committed
}
} else if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(SD)) {
RVal X = RVal::GetSymbolValue(SymMgr, IPD);
StateMgr.SetRVal(StateImpl, lval::DeclVal(IPD), X);
Chris Lattner
committed
}
return StateMgr.getPersistentState(StateImpl);
}
const ValueState* GRExprEngine::SetRVal(const ValueState* St, Expr* Ex,
RVal V) {
bool isBlkExpr = false;
if (Ex == CurrentStmt) {
isBlkExpr = getCFG().isBlkExpr(Ex);
if (!isBlkExpr)
return St;
}
return StateMgr.SetRVal(St, Ex, V, isBlkExpr, true);
//===----------------------------------------------------------------------===//
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
Builder = &builder;
Ted Kremenek
committed
EntryNode = builder.getLastNode();
CurrentStmt = S;
// Set up our simple checks.
// FIXME: This can probably be installed directly in GRCoreEngine, obviating
// the need to do a copy every time we hit a block-level statement.
if (!MsgExprChecks.empty())
Builder->setObjCMsgExprAuditors((GRAuditor<ValueState>**) &MsgExprChecks[0],
(GRAuditor<ValueState>**) (&MsgExprChecks[0] + MsgExprChecks.size()));
if (!CallChecks.empty())
Builder->setCallExprAuditors((GRAuditor<ValueState>**) &CallChecks[0],
(GRAuditor<ValueState>**) (&CallChecks[0] + CallChecks.size()));
Loading
Loading full blame...