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/GRTransferFuncs.h"
#include "llvm/Support/Streams.h"
using namespace clang;
using llvm::dyn_cast;
using llvm::cast;
using llvm::APSInt;
Ted Kremenek
committed
GRExprEngine::SetRVal(StateTy St, Expr* Ex, const RVal& V) {
if (!StateCleaned) {
St = RemoveDeadBindings(CurrentStmt, St);
StateCleaned = true;
}
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);
const GRExprEngine::StateTy::BufferTy&
GRExprEngine::SetRVal(StateTy St, Expr* Ex, const RVal::BufferTy& RB,
StateTy::BufferTy& RetBuf) {
assert (RetBuf.empty());
for (RVal::BufferTy::const_iterator I = RB.begin(), E = RB.end(); I!=E; ++I)
RetBuf.push_back(SetRVal(St, Ex, *I));
return RetBuf;
}
GRExprEngine::SetRVal(StateTy St, const LVal& LV, const RVal& RV) {
if (!StateCleaned) {
St = RemoveDeadBindings(CurrentStmt, St);
StateCleaned = true;
}
return StateMgr.SetRVal(St, LV, RV);
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
GRExprEngine::StateTy
GRExprEngine::MarkBranch(StateTy 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();
return SetBlkExprRVal(St, B, UninitializedVal(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();
return SetBlkExprRVal(St, C, UninitializedVal(Ex));
}
case Stmt::ChooseExprClass: { // ?:
ChooseExpr* C = cast<ChooseExpr>(Terminator);
Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
return SetBlkExprRVal(St, C, UninitializedVal(Ex));
}
}
}
void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term,
BranchNodeBuilder& builder) {
// Remove old bindings for subexpressions.
StateTy PrevState = StateMgr.RemoveSubExprBindings(builder.getState());
Ted Kremenek
committed
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
builder.markInfeasible(false);
// Get the current block counter.
GRBlockCounter BC = builder.getBlockCounter();
unsigned BlockID = builder.getTargetBlock(true)->getBlockID();
unsigned NumVisited = BC.getNumVisited(BlockID);
if (NumVisited < 1) builder.generateNode(PrevState, true);
else builder.markInfeasible(true);
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;
case RVal::UninitializedKind: {
NodeTy* N = builder.generateNode(PrevState, true);
if (N) {
N->markAsSink();
UninitBranches.insert(N);
}
builder.markInfeasible(false);
return;
}
}
Ted Kremenek
committed
// Get the current block counter.
GRBlockCounter BC = builder.getBlockCounter();
unsigned BlockID = builder.getTargetBlock(true)->getBlockID();
unsigned NumVisited = BC.getNumVisited(BlockID);
if (isa<nonlval::ConcreteInt>(V) ||
BC.getNumVisited(builder.getTargetBlock(true)->getBlockID()) < 1) {
// Process the true branch.
bool isFeasible = true;
StateTy St = Assume(PrevState, V, true, isFeasible);
if (isFeasible)
builder.generateNode(MarkBranch(St, Term, true), true);
else
builder.markInfeasible(true);
else
builder.markInfeasible(true);
BlockID = builder.getTargetBlock(false)->getBlockID();
NumVisited = BC.getNumVisited(BlockID);
if (isa<nonlval::ConcreteInt>(V) ||
BC.getNumVisited(builder.getTargetBlock(false)->getBlockID()) < 1) {
// Process the false branch.
bool isFeasible = false;
StateTy St = Assume(PrevState, V, false, isFeasible);
Loading
Loading full blame...