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"
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);
}
GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx)
: CoreEngine(cfg, CD, Ctx, *this),
G(CoreEngine.getGraph()),
Liveness(G.getCFG()),
Builder(NULL),
StateMgr(G.getContext(), G.getAllocator()),
BasicVals(StateMgr.getBasicValueFactory()),
TF(NULL), // FIXME
SymMgr(StateMgr.getSymbolManager()),
Ted Kremenek
committed
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())) {
// Compute liveness information.
Liveness.runOnCFG(G.getCFG());
Liveness.runOnAllBlocks(G.getCFG(), NULL, true);
}
GRExprEngine::~GRExprEngine() {
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;
};
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
void GRExprEngine::EmitWarnings(Diagnostic& Diag, PathDiagnosticClient* PD) {
for (bug_type_iterator I = bug_types_begin(), E = bug_types_end(); I!=E; ++I){
BugReporter BR(Diag, PD, getContext(), *this);
(*I)->EmitWarnings(BR);
}
for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
I != E; ++I) {
BugReporter BR(Diag, PD, getContext(), *this);
(*I)->EmitWarnings(BR);
}
for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
I != E; ++I) {
BugReporter BR(Diag, PD, getContext(), *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);
}
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.BindVar(StateImpl, VD, X);
}
} else if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(SD)) {
RVal X = RVal::GetSymbolValue(SymMgr, IPD);
StateMgr.BindVar(StateImpl, IPD, X);
Chris Lattner
committed
}
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;
}
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()));
// Create the cleaned state.
Ted Kremenek
committed
CleanedState = StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt,
Liveness, DeadSymbols);
// Process any special transfer function for dead symbols.
NodeSet Tmp;
if (DeadSymbols.empty())
Ted Kremenek
committed
Tmp.Add(EntryNode);
else {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Ted Kremenek
committed
SaveOr OldHasGen(Builder->HasGeneratedNode);
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
Builder->PurgingDeadSymbols = true;
TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
CleanedState, DeadSymbols);
Ted Kremenek
committed
if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
Tmp.Add(EntryNode);
}
Ted Kremenek
committed
bool HasAutoGenerated = false;
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Ted Kremenek
committed
NodeSet Dst;
// Set the cleaned state.
Ted Kremenek
committed
Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
// Visit the statement.
Ted Kremenek
committed
Visit(S, *I, Dst);
// Do we need to auto-generate a node? We only need to do this to generate
// a node with a "cleaned" state; GRCoreEngine will actually handle
// auto-transitions for other cases.
if (Dst.size() == 1 && *Dst.begin() == EntryNode
&& !Builder->HasGeneratedNode && !HasAutoGenerated) {
HasAutoGenerated = true;
builder.generateNode(S, GetState(EntryNode), *I);
}
}
// NULL out these variables to cleanup.
Ted Kremenek
committed
CleanedState = NULL;
EntryNode = NULL;
CurrentStmt = NULL;
Builder = NULL;
}
void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
// FIXME: add metadata to the CFG so that we can disable
// this check when we KNOW that there is no block-level subexpression.
// The motivation is that this check requires a hashtable lookup.
if (S != CurrentStmt && getCFG().isBlkExpr(S)) {
Dst.Add(Pred);
return;
}
switch (S->getStmtClass()) {
default:
// Cases we intentionally have "default" handle:
// AddrLabelExpr, IntegerLiteral, CharacterLiteral
Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
break;
case Stmt::ArraySubscriptExprClass:
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst, false);
break;
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
case Stmt::AsmStmtClass:
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(S);
if (B->isLogicalOp()) {
VisitLogicalExpr(B, Pred, Dst);
break;
}
else if (B->getOpcode() == BinaryOperator::Comma) {
ValueState* St = GetState(Pred);
MakeNode(Dst, B, Pred, SetRVal(St, B, GetRVal(St, B->getRHS())));
break;
}
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
break;
}
case Stmt::CallExprClass: {
CallExpr* C = cast<CallExpr>(S);
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
break;
}
case Stmt::CastExprClass: {
CastExpr* C = cast<CastExpr>(S);
VisitCast(C, C->getSubExpr(), Pred, Dst);
break;
}
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
case Stmt::ChooseExprClass: { // __builtin_choose_expr
ChooseExpr* C = cast<ChooseExpr>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
break;
}
case Stmt::CompoundAssignOperatorClass:
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
break;
case Stmt::ConditionalOperatorClass: { // '?' operator
ConditionalOperator* C = cast<ConditionalOperator>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
break;
}
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
break;
case Stmt::DeclStmtClass:
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
break;
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr* C = cast<ImplicitCastExpr>(S);
VisitCast(C, C->getSubExpr(), Pred, Dst);
break;
}
Ted Kremenek
committed
case Stmt::MemberExprClass: {
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst, false);
break;
}
case Stmt::ObjCMessageExprClass: {
VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
break;
}
case Stmt::ParenExprClass:
Visit(cast<ParenExpr>(S)->getSubExpr()->IgnoreParens(), Pred, Dst);
break;
case Stmt::ReturnStmtClass:
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
break;
case Stmt::SizeOfAlignOfTypeExprClass:
VisitSizeOfAlignOfTypeExpr(cast<SizeOfAlignOfTypeExpr>(S), Pred, Dst);
break;
case Stmt::StmtExprClass: {
StmtExpr* SE = cast<StmtExpr>(S);
ValueState* St = GetState(Pred);
// FIXME: Not certain if we can have empty StmtExprs. If so, we should
// probably just remove these from the CFG.
assert (!SE->getSubStmt()->body_empty());
if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin()))
MakeNode(Dst, SE, Pred, SetRVal(St, SE, GetRVal(St, LastExpr)));
else
Dst.Add(Pred);
break;
}
case Stmt::UnaryOperatorClass:
VisitUnaryOperator(cast<UnaryOperator>(S), Pred, Dst, false);
break;
}
}
void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
Ex = Ex->IgnoreParens();
if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) {
Dst.Add(Pred);
return;
}
switch (Ex->getStmtClass()) {
default:
Visit(Ex, Pred, Dst);
return;
case Stmt::ArraySubscriptExprClass:
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
return;
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
case Stmt::UnaryOperatorClass:
VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
return;
case Stmt::MemberExprClass:
VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
return;
}
}
//===----------------------------------------------------------------------===//
// Block entrance. (Update counters).
//===----------------------------------------------------------------------===//
bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, ValueState*,
GRBlockCounter BC) {
return BC.getNumVisited(B->getBlockID()) < 3;
}
//===----------------------------------------------------------------------===//
// Branch processing.
//===----------------------------------------------------------------------===//
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));
}
}
}
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.
void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) {
ValueState* St = builder.getState();
RVal V = GetRVal(St, builder.getTarget());
// Three possibilities:
//
// (1) We know the computed label.
Ted Kremenek
committed
// (2) The label is NULL (or some other constant), or Undefined.
// (3) We have no clue about the label. Dispatch to all targets.
//
typedef IndirectGotoNodeBuilder::iterator iterator;
if (isa<lval::GotoLabel>(V)) {
LabelStmt* L = cast<lval::GotoLabel>(V).getLabel();
for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
if (I.getLabel() == L) {
builder.generateNode(I, St);
return;
}
}
assert (false && "No block with label.");
return;
}
Ted Kremenek
committed
if (isa<lval::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
// Dispatch to the first target and mark it as a sink.
NodeTy* N = builder.generateNode(builder.begin(), St, true);
Ted Kremenek
committed
UndefBranches.insert(N);
return;
}
// This is really a catch-all. We don't support symbolics yet.
assert (V.isUnknown());
for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
NodeTy* Pred, NodeSet& Dst) {
assert (Ex == CurrentStmt && getCFG().isBlkExpr(Ex));
ValueState* St = GetState(Pred);
RVal X = GetBlkExprRVal(St, Ex);
assert (X.isUndef());
Expr* SE = (Expr*) cast<UndefinedVal>(X).getData();
assert (SE);
X = GetBlkExprRVal(St, SE);
// Make sure that we invalidate the previous binding.
MakeNode(Dst, Ex, Pred, StateMgr.SetRVal(St, Ex, X, true, true));
}
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
typedef SwitchNodeBuilder::iterator iterator;
ValueState* St = builder.getState();
Expr* CondE = builder.getCondition();
RVal CondV = GetRVal(St, CondE);
Ted Kremenek
committed
if (CondV.isUndef()) {
NodeTy* N = builder.generateDefaultCaseNode(St, true);
Ted Kremenek
committed
UndefBranches.insert(N);
return;
}
ValueState* DefaultSt = St;
// While most of this can be assumed (such as the signedness), having it
// just computed makes sure everything makes the same assumptions end-to-end.
unsigned bits = getContext().getTypeSize(CondE->getType());
APSInt V1(bits, false);
APSInt V2 = V1;
bool DefaultFeasible = false;
for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) {
CaseStmt* Case = cast<CaseStmt>(I.getCase());
// Evaluate the case.
if (!Case->getLHS()->isIntegerConstantExpr(V1, getContext(), 0, true)) {
assert (false && "Case condition must evaluate to an integer constant.");
return;
}
// Get the RHS of the case, if it exists.
if (Expr* E = Case->getRHS()) {
if (!E->isIntegerConstantExpr(V2, getContext(), 0, true)) {
assert (false &&
"Case condition (RHS) must evaluate to an integer constant.");
return ;
}
assert (V1 <= V2);
}
else
V2 = V1;
// FIXME: Eventually we should replace the logic below with a range
// comparison, rather than concretize the values within the range.
// This should be easy once we have "ranges" for NonLVals.
nonlval::ConcreteInt CaseVal(BasicVals.getValue(V1));
RVal Res = EvalBinOp(BinaryOperator::EQ, CondV, CaseVal);
// Now "assume" that the case matches.
Ted Kremenek
committed
bool isFeasible = false;
ValueState* StNew = Assume(St, Res, true, isFeasible);
if (isFeasible) {
builder.generateCaseStmtNode(I, StNew);
// If CondV evaluates to a constant, then we know that this
// is the *only* case that we can take, so stop evaluating the
// others.
if (isa<nonlval::ConcreteInt>(CondV))
return;
}
// Now "assume" that the case doesn't match. Add this state
// to the default state (if it is feasible).
Ted Kremenek
committed
isFeasible = false;
StNew = Assume(DefaultSt, Res, false, isFeasible);
if (isFeasible) {
DefaultFeasible = true;
DefaultSt = StNew;
// Concretize the next value in the range.
if (V1 == V2)
break;
++V1;
} while (true);
}
// If we reach here, than we know that the default branch is
// possible.
if (DefaultFeasible) builder.generateDefaultCaseNode(DefaultSt);
}
//===----------------------------------------------------------------------===//
// Transfer functions: logical operations ('&&', '||').
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
NodeSet& Dst) {
assert (B->getOpcode() == BinaryOperator::LAnd ||
B->getOpcode() == BinaryOperator::LOr);
assert (B == CurrentStmt && getCFG().isBlkExpr(B));
ValueState* St = GetState(Pred);
RVal X = GetBlkExprRVal(St, B);
Ted Kremenek
committed
assert (X.isUndef());
Ted Kremenek
committed
Expr* Ex = (Expr*) cast<UndefinedVal>(X).getData();
assert (Ex);
if (Ex == B->getRHS()) {
X = GetBlkExprRVal(St, Ex);
Ted Kremenek
committed
// Handle undefined values.
Ted Kremenek
committed
Ted Kremenek
committed
if (X.isUndef()) {
MakeNode(Dst, B, Pred, SetBlkExprRVal(St, B, X));
Ted Kremenek
committed
return;
}
// We took the RHS. Because the value of the '&&' or '||' expression must
// evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
// or 1. Alternatively, we could take a lazy approach, and calculate this
// value later when necessary. We don't have the machinery in place for
// this right now, and since most logical expressions are used for branches,
// the payoff is not likely to be large. Instead, we do eager evaluation.
bool isFeasible = false;
ValueState* NewState = Assume(St, X, true, isFeasible);
if (isFeasible)
MakeNode(Dst, B, Pred,
SetBlkExprRVal(NewState, B, MakeConstantVal(1U, B)));
isFeasible = false;
NewState = Assume(St, X, false, isFeasible);
if (isFeasible)
MakeNode(Dst, B, Pred,
SetBlkExprRVal(NewState, B, MakeConstantVal(0U, B)));
}
else {
// We took the LHS expression. Depending on whether we are '&&' or
// '||' we know what the value of the expression is via properties of
// the short-circuiting.
X = MakeConstantVal( B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, B);
MakeNode(Dst, B, Pred, SetBlkExprRVal(St, B, X));
}
//===----------------------------------------------------------------------===//
// Transfer functions: Loads and stores.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst,
bool asLVal) {
ValueState* St = GetState(Pred);
RVal X = RVal::MakeVal(BasicVals, D);
if (asLVal)
MakeNode(Dst, D, Pred, SetRVal(St, D, cast<LVal>(X)));
else {
RVal V = isa<lval::DeclVal>(X) ? GetRVal(St, cast<LVal>(X)) : X;
MakeNode(Dst, D, Pred, SetRVal(St, D, V));
}
/// VisitArraySubscriptExpr - Transfer function for array accesses
void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred,
NodeSet& Dst, bool asLVal) {
Expr* Base = A->getBase()->IgnoreParens();
Expr* Idx = A->getIdx()->IgnoreParens();
// Always visit the base as an LVal expression. This computes the
// abstract address of the base object.
NodeSet Tmp;
Ted Kremenek
committed
if (LVal::IsLValType(Base->getType())) // Base always is an LVal.
Visit(Base, Pred, Tmp);
else
VisitLVal(Base, Pred, Tmp);
for (NodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
// Evaluate the index.
NodeSet Tmp2;
Visit(Idx, *I1, Tmp2);
for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2) {
ValueState* St = GetState(*I2);
RVal BaseV = GetRVal(St, Base);
RVal IdxV = GetRVal(St, Idx);
// If IdxV is 0, return just BaseV.
bool useBase = false;
if (nonlval::ConcreteInt* IdxInt = dyn_cast<nonlval::ConcreteInt>(&IdxV))
useBase = IdxInt->getValue() == 0;
RVal V = useBase ? BaseV : lval::ArrayOffset::Make(BasicVals, BaseV,IdxV);
if (asLVal)
MakeNode(Dst, A, *I2, SetRVal(St, A, V));
else
EvalLoad(Dst, A, *I2, St, V);
}
Ted Kremenek
committed
/// VisitMemberExpr - Transfer function for member expressions.
void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred,
NodeSet& Dst, bool asLVal) {
Expr* Base = M->getBase()->IgnoreParens();
// Always visit the base as an LVal expression. This computes the
// abstract address of the base object.
Ted Kremenek
committed
NodeSet Tmp;
Ted Kremenek
committed
if (asLVal) {
Ted Kremenek
committed
if (LVal::IsLValType(Base->getType())) // Base always is an LVal.
Ted Kremenek
committed
Visit(Base, Pred, Tmp);
else
VisitLVal(Base, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
ValueState* St = GetState(*I);
RVal BaseV = GetRVal(St, Base);
RVal V = lval::FieldOffset::Make(BasicVals, GetRVal(St, Base),
M->getMemberDecl());
MakeNode(Dst, M, *I, SetRVal(St, M, V));
}
return;
}
// Evaluate the base. Can be an LVal or NonLVal (depends on whether
// or not isArrow() is true).
Visit(Base, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Ted Kremenek
committed
ValueState* St = GetState(*I);
Ted Kremenek
committed
RVal BaseV = GetRVal(St, Base);
Ted Kremenek
committed
Ted Kremenek
committed
if (LVal::IsLValType(Base->getType())) {
Ted Kremenek
committed
assert (M->isArrow());
RVal V = lval::FieldOffset::Make(BasicVals, GetRVal(St, Base),
M->getMemberDecl());
EvalLoad(Dst, M, *I, St, V);
Ted Kremenek
committed
}
else {
assert (!M->isArrow());
if (BaseV.isUnknownOrUndef()) {
MakeNode(Dst, M, *I, SetRVal(St, M, BaseV));
continue;
}
// FIXME: Implement nonlval objects representing struct temporaries.
assert (isa<NonLVal>(BaseV));
MakeNode(Dst, M, *I, SetRVal(St, M, UnknownVal()));
}
Ted Kremenek
committed
}
}
void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
ValueState* St, RVal location, RVal Val) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
// Evaluate the location (checks for bad dereferences).
St = EvalLocation(Ex, Pred, St, location);
if (!St)
return;
// Proceed with the store.
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
assert (!location.isUndef());
Ted Kremenek
committed
TF->EvalStore(Dst, *this, *Builder, Ex, Pred, St, location, Val);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
TF->GRTransferFuncs::EvalStore(Dst, *this, *Builder, Ex, Pred, St,
location, Val);
}
void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
ValueState* St, RVal location, bool CheckOnly) {
// Evaluate the location (checks for bad dereferences).
St = EvalLocation(Ex, Pred, St, location, true);
if (!St)
return;
// Proceed with the load.
// FIXME: Currently symbolic analysis "generates" new symbols
// for the contents of values. We need a better approach.
// FIXME: The "CheckOnly" option exists only because Array and Field
// loads aren't fully implemented. Eventually this option will go away.
if (CheckOnly)
MakeNode(Dst, Ex, Pred, St);
else if (location.isUnknown()) {
// This is important. We must nuke the old binding.
MakeNode(Dst, Ex, Pred, SetRVal(St, Ex, UnknownVal()));
}
else
MakeNode(Dst, Ex, Pred, SetRVal(St, Ex, GetRVal(St, cast<LVal>(location),
Ex->getType())));
}
ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
ValueState* St, RVal location,
bool isLoad) {
// Check for loads/stores from/to undefined values.
if (location.isUndef()) {
ProgramPoint::Kind K =
isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;
if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, K)) {
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Succ->markAsSink();
UndefDeref.insert(Succ);
}
return NULL;
}
// Check for loads/stores from/to unknown locations. Treat as No-Ops.
if (location.isUnknown())
return St;
// During a load, one of two possible situations arise:
// (1) A crash, because the location (pointer) was NULL.
// (2) The location (pointer) is not NULL, and the dereference works.
//
// We add these assumptions.
LVal LV = cast<LVal>(location);
// "Assume" that the pointer is not NULL.
bool isFeasibleNotNull = false;
ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
// "Assume" that the pointer is NULL.