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"
Ted Kremenek
committed
#include "clang/Basic/SourceManager.h"
Ted Kremenek
committed
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#include <sstream>
#endif
Ted Kremenek
committed
// 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;
};
using namespace clang;
using llvm::dyn_cast;
using llvm::cast;
using llvm::APSInt;
Ted Kremenek
committed
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) {
VarDecl* VD = cast<VarDecl>(const_cast<ScopedDecl*>(I->first));
if (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD)) {
RVal X = RVal::GetSymbolValue(SymMgr, VD);
StateMgr.BindVar(StateImpl, VD, X);
}
}
return StateMgr.getPersistentState(StateImpl);
}
ValueState* GRExprEngine::SetRVal(ValueState* St, Expr* Ex, RVal V) {
bool isBlkExpr = false;
if (Ex == CurrentStmt) {
isBlkExpr = getCFG().isBlkExpr(Ex);
if (!isBlkExpr)
return St;
}
Ted Kremenek
committed
return StateMgr.SetRVal(St, Ex, V, isBlkExpr, false);
ValueState* GRExprEngine::MarkBranch(ValueState* St, Stmt* Terminator,
bool branchTaken) {
switch (Terminator->getStmtClass()) {
default:
return St;
case Stmt::BinaryOperatorClass: { // '&&' and '||'
BinaryOperator* B = cast<BinaryOperator>(Terminator);
BinaryOperator::Opcode Op = B->getOpcode();
assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr);
// For &&, if we take the true branch, then the value of the whole
// expression is that of the RHS expression.
//
// For ||, if we take the false branch, then the value of the whole
// expression is that of the RHS expression.
Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) ||
(Op == BinaryOperator::LOr && !branchTaken)
? B->getRHS() : B->getLHS();
Ted Kremenek
committed
return SetBlkExprRVal(St, B, UndefinedVal(Ex));
}
case Stmt::ConditionalOperatorClass: { // ?:
ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
// For ?, if branchTaken == true then the value is either the LHS or
// the condition itself. (GNU extension).
Expr* Ex;
if (branchTaken)
Ex = C->getLHS() ? C->getLHS() : C->getCond();
else
Ex = C->getRHS();
Ted Kremenek
committed
return SetBlkExprRVal(St, C, UndefinedVal(Ex));
}
case Stmt::ChooseExprClass: { // ?:
ChooseExpr* C = cast<ChooseExpr>(Terminator);
Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
Ted Kremenek
committed
return SetBlkExprRVal(St, C, UndefinedVal(Ex));
}
}
}
Ted Kremenek
committed
bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, ValueState*,
GRBlockCounter BC) {
return BC.getNumVisited(B->getBlockID()) < 3;
}
void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term,
BranchNodeBuilder& builder) {
// Remove old bindings for subexpressions.
ValueState* PrevState = StateMgr.RemoveSubExprBindings(builder.getState());
Ted Kremenek
committed
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
builder.markInfeasible(false);
return;
}
RVal V = GetRVal(PrevState, Condition);
switch (V.getBaseKind()) {
default:
break;
case RVal::UnknownKind:
Ted Kremenek
committed
builder.generateNode(MarkBranch(PrevState, Term, true), true);
builder.generateNode(MarkBranch(PrevState, Term, false), false);
return;
Ted Kremenek
committed
case RVal::UndefinedKind: {
NodeTy* N = builder.generateNode(PrevState, true);
if (N) {
N->markAsSink();
Ted Kremenek
committed
UndefBranches.insert(N);
}
builder.markInfeasible(false);
return;
}
}
Ted Kremenek
committed
// Process the true branch.
Ted Kremenek
committed
bool isFeasible = false;
Ted Kremenek
committed
ValueState* St = Assume(PrevState, V, true, isFeasible);
if (isFeasible)
builder.generateNode(MarkBranch(St, Term, true), true);
else
builder.markInfeasible(true);
Ted Kremenek
committed
// Process the false branch.
Ted Kremenek
committed
isFeasible = false;
St = Assume(PrevState, V, false, isFeasible);
Ted Kremenek
committed
if (isFeasible)
builder.generateNode(MarkBranch(St, Term, false), false);
else
builder.markInfeasible(false);
}
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
Loading
Loading full blame...