Newer
Older
Ted Kremenek
committed
Dst.Add(Pred);
return;
}
Ex = Ex->IgnoreParens();
if (isa<DeclRefExpr>(Ex)) {
Dst.Add(Pred);
if (UnaryOperator* U = dyn_cast<UnaryOperator>(Ex))
if (U->getOpcode() == UnaryOperator::Deref) {
VisitDeref(U, Pred, Dst, true);
Visit(Ex, Pred, Dst);
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
void GRExprEngine::VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
AsmStmt::outputs_iterator I,
AsmStmt::outputs_iterator E,
NodeTy* Pred, NodeSet& Dst) {
if (I == E) {
VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
return;
}
NodeSet Tmp;
VisitLVal(*I, Pred, Tmp);
++I;
for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
}
void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
NodeTy* Pred, NodeSet& Dst) {
if (I == E) {
// We have processed both the inputs and the outputs. All of the outputs
// should evaluate to LVals. Nuke all of their values.
// FIXME: Some day in the future it would be nice to allow a "plug-in"
// which interprets the inline asm and stores proper results in the
// outputs.
ValueState* St = GetState(Pred);
for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
RVal X = GetLVal(St, *OI);
assert (!isa<NonLVal>(X));
if (isa<LVal>(X))
St = SetRVal(St, cast<LVal>(X), UnknownVal());
}
Nodify(Dst, A, Pred, St);
return;
}
NodeSet Tmp;
Visit(*I, Pred, Tmp);
++I;
for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
}
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
GRExprEngine::NodeTy* Pred,
GRExprEngine::NodeSet& Dst) {
Ted Kremenek
committed
NodeSet S1;
if (B->isAssignmentOp())
VisitLVal(B->getLHS(), Pred, S1);
else
Visit(B->getLHS(), Pred, S1);
Ted Kremenek
committed
for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) {
Ted Kremenek
committed
NodeTy* N1 = *I1;
Ted Kremenek
committed
// When getting the value for the LHS, check if we are in an assignment.
// In such cases, we want to (initially) treat the LHS as an LVal,
// so we use GetLVal instead of GetRVal so that DeclRefExpr's are
// evaluated to LValDecl's instead of to an NonLVal.
RVal LeftV = B->isAssignmentOp() ? GetLVal(GetState(N1), B->getLHS())
: GetRVal(GetState(N1), B->getLHS());
// Visit the RHS...
NodeSet S2;
Ted Kremenek
committed
Visit(B->getRHS(), N1, S2);
// Process the binary operator.
Ted Kremenek
committed
for (NodeSet::iterator I2 = S2.begin(), E2 = S2.end(); I2 != E2; ++I2) {
Ted Kremenek
committed
NodeTy* N2 = *I2;
ValueState* St = GetState(N2);
Expr* RHS = B->getRHS();
RVal RightV = GetRVal(St, RHS);
Ted Kremenek
committed
BinaryOperator::Opcode Op = B->getOpcode();
if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
&& RHS->getType()->isIntegerType()) {
Ted Kremenek
committed
// Check if the denominator is undefined.
if (!RightV.isUnknown()) {
Ted Kremenek
committed
if (RightV.isUndef()) {
NodeTy* DivUndef = Builder->generateNode(B, St, N2);
Ted Kremenek
committed
if (DivUndef) {
DivUndef->markAsSink();
ExplicitBadDivides.insert(DivUndef);
}
continue;
}
// Check for divide/remainder-by-zero.
//
Ted Kremenek
committed
// First, "assume" that the denominator is 0 or undefined.
bool isFeasibleZero = false;
ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero);
// Second, "assume" that the denominator cannot be 0.
bool isFeasibleNotZero = false;
St = Assume(St, RightV, true, isFeasibleNotZero);
// Create the node for the divide-by-zero (if it occurred).
if (isFeasibleZero)
Ted Kremenek
committed
if (NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2)) {
DivZeroNode->markAsSink();
if (isFeasibleNotZero)
ImplicitBadDivides.insert(DivZeroNode);
else
ExplicitBadDivides.insert(DivZeroNode);
if (!isFeasibleNotZero)
continue;
}
// Fall-through. The logic below processes the divide.
}
Ted Kremenek
committed
if (Op <= BinaryOperator::Or) {
// Process non-assignements except commas or short-circuited
// logical expressions (LAnd and LOr).
RVal Result = EvalBinOp(Op, LeftV, RightV);
if (Result.isUnknown()) {
Dst.Add(N2);
Ted Kremenek
committed
if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
// The operands were not undefined, but the result is undefined.
if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) {
UndefNode->markAsSink();
UndefResults.insert(UndefNode);
}
continue;
}
Nodify(Dst, B, N2, SetRVal(St, B, Result));
continue;
}
// Process assignments.
switch (Op) {
Ted Kremenek
committed
case BinaryOperator::Assign: {
// Simple assignments.
Ted Kremenek
committed
if (LeftV.isUndef()) {
HandleUndefinedStore(B, N2);
continue;
}
Ted Kremenek
committed
// EXPERIMENTAL: "Conjured" symbols.
if (RightV.isUnknown()) {
unsigned Count = Builder->getCurrentBlockCount();
SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
RightV = B->getRHS()->getType()->isPointerType()
? cast<RVal>(lval::SymbolVal(Sym))
: cast<RVal>(nonlval::SymbolVal(Sym));
}
// Even if the LHS evaluates to an unknown L-Value, the entire
// expression still evaluates to the RHS.
if (LeftV.isUnknown()) {
St = SetRVal(St, B, RightV);
break;
}
Ted Kremenek
committed
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
St = SetRVal(SetRVal(St, B, RightV), cast<LVal>(LeftV), RightV);
Ted Kremenek
committed
break;
}
// Compound assignment operators.
default: {
assert (B->isCompoundAssignmentOp());
if (Op >= BinaryOperator::AndAssign)
((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And);
else
((int&) Op) -= BinaryOperator::MulAssign;
Ted Kremenek
committed
// Check if the LHS is undefined.
Ted Kremenek
committed
if (LeftV.isUndef()) {
HandleUndefinedStore(B, N2);
continue;
}
if (LeftV.isUnknown()) {
assert (isa<UnknownVal>(GetRVal(St, B)));
Dst.Add(N2);
continue;
}
// At this pointer we know that the LHS evaluates to an LVal
// that is neither "Unknown" or "Undefined."
LVal LeftLV = cast<LVal>(LeftV);
// Fetch the value of the LHS (the value of the variable, etc.).
RVal V = GetRVal(GetState(N1), LeftLV, B->getLHS()->getType());
Ted Kremenek
committed
// Propagate undefined value (left-side). We
// propogate undefined values for the RHS below when
// we also check for divide-by-zero.
Ted Kremenek
committed
if (V.isUndef()) {
St = SetRVal(St, B, V);
break;
}
// Propagate unknown values.
if (V.isUnknown()) {
// The value bound to LeftV is unknown. Thus we just
// propagate the current node (as "B" is already bound to nothing).
assert (isa<UnknownVal>(GetRVal(St, B)));
Dst.Add(N2);
continue;
}
if (RightV.isUnknown()) {
assert (isa<UnknownVal>(GetRVal(St, B)));
St = SetRVal(St, LeftLV, UnknownVal());
break;
}
// At this point:
//
Ted Kremenek
committed
// The LHS is not Undef/Unknown.
// The RHS is not Unknown.
// Get the computation type.
QualType CTy = cast<CompoundAssignOperator>(B)->getComputationType();
// Perform promotions.
V = EvalCast(V, CTy);
// Evaluate operands and promote to result type.
if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
&& RHS->getType()->isIntegerType()) {
Ted Kremenek
committed
// Check if the denominator is undefined.
Ted Kremenek
committed
if (RightV.isUndef()) {
NodeTy* DivUndef = Builder->generateNode(B, St, N2);
Ted Kremenek
committed
if (DivUndef) {
DivUndef->markAsSink();
ExplicitBadDivides.insert(DivUndef);
}
continue;
}
// First, "assume" that the denominator is 0.
bool isFeasibleZero = false;
ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero);
// Second, "assume" that the denominator cannot be 0.
bool isFeasibleNotZero = false;
St = Assume(St, RightV, true, isFeasibleNotZero);
// Create the node for the divide-by-zero error (if it occurred).
if (isFeasibleZero) {
NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2);
if (DivZeroNode) {
DivZeroNode->markAsSink();
if (isFeasibleNotZero)
ImplicitBadDivides.insert(DivZeroNode);
else
ExplicitBadDivides.insert(DivZeroNode);
}
}
if (!isFeasibleNotZero)
continue;
// Fall-through. The logic below processes the divide.
}
else {
Ted Kremenek
committed
// Propagate undefined values (right-side).
Ted Kremenek
committed
if (RightV.isUndef()) {
St = SetRVal(SetRVal(St, B, RightV), LeftLV, RightV);
break;
}
}
RVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType());
Ted Kremenek
committed
if (Result.isUndef()) {
// The operands were not undefined, but the result is undefined.
if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) {
UndefNode->markAsSink();
UndefResults.insert(UndefNode);
}
continue;
}
St = SetRVal(SetRVal(St, B, Result), LeftLV, Result);
Ted Kremenek
committed
}
Nodify(Dst, B, N2, St);
}
}
}
Ted Kremenek
committed
void GRExprEngine::HandleUndefinedStore(Stmt* S, NodeTy* Pred) {
NodeTy* N = Builder->generateNode(S, GetState(Pred), Pred);
N->markAsSink();
Ted Kremenek
committed
UndefStores.insert(N);
void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
Ted Kremenek
committed
// 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.
Ted Kremenek
committed
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;
Ted Kremenek
committed
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);
Nodify(Dst, B, Pred, SetRVal(St, B, GetRVal(St, B->getRHS())));
break;
}
Ted Kremenek
committed
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);
Ted Kremenek
committed
break;
}
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst);
break;
Ted Kremenek
committed
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;
}
case Stmt::ParenExprClass:
Visit(cast<ParenExpr>(S)->getSubExpr(), 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()))
Nodify(Dst, SE, Pred, SetRVal(St, SE, GetRVal(St, LastExpr)));
else
Dst.Add(Pred);
break;
}
// FIXME: We may wish to always bind state to ReturnStmts so
// that users can quickly query what was the state at the
// exit points of a function.
case Stmt::ReturnStmtClass: {
if (Expr* R = cast<ReturnStmt>(S)->getRetValue())
Visit(R, Pred, Dst);
else
Dst.Add(Pred);
break;
}
case Stmt::UnaryOperatorClass: {
UnaryOperator* U = cast<UnaryOperator>(S);
switch (U->getOpcode()) {
case UnaryOperator::Deref: VisitDeref(U, Pred, Dst); break;
case UnaryOperator::Plus: Visit(U->getSubExpr(), Pred, Dst); break;
case UnaryOperator::SizeOf: VisitSizeOfExpr(U, Pred, Dst); break;
default: VisitUnaryOperator(U, Pred, Dst); break;
}
}
}
//===----------------------------------------------------------------------===//
// "Assume" logic.
//===----------------------------------------------------------------------===//
ValueState* GRExprEngine::Assume(ValueState* St, LVal Cond,
bool Assumption,
bool& isFeasible) {
switch (Cond.getSubKind()) {
default:
assert (false && "'Assume' not implemented for this LVal.");
return St;
Ted Kremenek
committed
case lval::SymbolValKind:
if (Assumption)
return AssumeSymNE(St, cast<lval::SymbolVal>(Cond).getSymbol(),
BasicVals.getZeroWithPtrWidth(), isFeasible);
Ted Kremenek
committed
else
return AssumeSymEQ(St, cast<lval::SymbolVal>(Cond).getSymbol(),
BasicVals.getZeroWithPtrWidth(), isFeasible);
Ted Kremenek
committed
Ted Kremenek
committed
case lval::DeclValKind:
Ted Kremenek
committed
case lval::FuncValKind:
case lval::GotoLabelKind:
isFeasible = Assumption;
return St;
Ted Kremenek
committed
case lval::ConcreteIntKind: {
bool b = cast<lval::ConcreteInt>(Cond).getValue() != 0;
isFeasible = b ? Assumption : !Assumption;
return St;
}
}
}
ValueState* GRExprEngine::Assume(ValueState* St, NonLVal Cond,
Ted Kremenek
committed
bool Assumption,
bool& isFeasible) {
switch (Cond.getSubKind()) {
default:
assert (false && "'Assume' not implemented for this NonLVal.");
return St;
Ted Kremenek
committed
case nonlval::SymbolValKind: {
nonlval::SymbolVal& SV = cast<nonlval::SymbolVal>(Cond);
Ted Kremenek
committed
SymbolID sym = SV.getSymbol();
if (Assumption)
return AssumeSymNE(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)),
Ted Kremenek
committed
isFeasible);
else
return AssumeSymEQ(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)),
Ted Kremenek
committed
isFeasible);
}
Ted Kremenek
committed
case nonlval::SymIntConstraintValKind:
return
AssumeSymInt(St, Assumption,
cast<nonlval::SymIntConstraintVal>(Cond).getConstraint(),
isFeasible);
case nonlval::ConcreteIntKind: {
bool b = cast<nonlval::ConcreteInt>(Cond).getValue() != 0;
isFeasible = b ? Assumption : !Assumption;
return St;
}
}
}
ValueState*
GRExprEngine::AssumeSymNE(ValueState* St, SymbolID sym,
Ted Kremenek
committed
const llvm::APSInt& V, bool& isFeasible) {
Ted Kremenek
committed
// First, determine if sym == X, where X != V.
if (const llvm::APSInt* X = St->getSymVal(sym)) {
Ted Kremenek
committed
isFeasible = *X != V;
return St;
}
// Second, determine if sym != V.
if (St->isNotEqual(sym, V)) {
Ted Kremenek
committed
isFeasible = true;
return St;
}
// If we reach here, sym is not a constant and we don't know if it is != V.
// Make that assumption.
isFeasible = true;
return StateMgr.AddNE(St, sym, V);
}
ValueState*
GRExprEngine::AssumeSymEQ(ValueState* St, SymbolID sym,
Ted Kremenek
committed
const llvm::APSInt& V, bool& isFeasible) {
// First, determine if sym == X, where X != V.
if (const llvm::APSInt* X = St->getSymVal(sym)) {
Ted Kremenek
committed
isFeasible = *X == V;
return St;
}
// Second, determine if sym != V.
if (St->isNotEqual(sym, V)) {
Ted Kremenek
committed
isFeasible = false;
return St;
}
// If we reach here, sym is not a constant and we don't know if it is == V.
// Make that assumption.
isFeasible = true;
return StateMgr.AddEQ(St, sym, V);
}
ValueState*
GRExprEngine::AssumeSymInt(ValueState* St, bool Assumption,
Ted Kremenek
committed
const SymIntConstraint& C, bool& isFeasible) {
switch (C.getOpcode()) {
default:
// No logic yet for other operators.
Ted Kremenek
committed
isFeasible = true;
Ted Kremenek
committed
return St;
case BinaryOperator::EQ:
if (Assumption)
return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible);
else
return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible);
case BinaryOperator::NE:
if (Assumption)
return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible);
else
return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible);
}
}
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
#ifndef NDEBUG
static GRExprEngine* GraphPrintCheckerState;
Ted Kremenek
committed
static SourceManager* GraphPrintSourceManager;
Ted Kremenek
committed
static ValueState::CheckerStatePrinter* GraphCheckerStatePrinter;
namespace llvm {
template<>
struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
public DefaultDOTGraphTraits {
static void PrintVarBindings(std::ostream& Out, ValueState* St) {
Out << "Variables:\\l";
bool isFirst = true;
for (ValueState::vb_iterator I=St->vb_begin(), E=St->vb_end(); I!=E;++I) {
if (isFirst)
isFirst = false;
else
Out << "\\l";
Out << ' ' << I.getKey()->getName() << " : ";
I.getData().print(Out);
}
}
static void PrintSubExprBindings(std::ostream& Out, ValueState* St){
bool isFirst = true;
for (ValueState::seb_iterator I=St->seb_begin(), E=St->seb_end();I!=E;++I) {
if (isFirst) {
Out << "\\l\\lSub-Expressions:\\l";
isFirst = false;
}
else
Out << "\\l";
Out << " (" << (void*) I.getKey() << ") ";
I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
}
static void PrintBlkExprBindings(std::ostream& Out, ValueState* St){
bool isFirst = true;
for (ValueState::beb_iterator I=St->beb_begin(), E=St->beb_end(); I!=E;++I){
if (isFirst) {
Out << "\\l\\lBlock-level Expressions:\\l";
isFirst = false;
}
else
Out << "\\l";
Out << " (" << (void*) I.getKey() << ") ";
I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
}
static void PrintEQ(std::ostream& Out, ValueState* St) {
ValueState::ConstEqTy CE = St->ConstEq;
if (CE.isEmpty())
return;
Out << "\\l\\|'==' constraints:";
for (ValueState::ConstEqTy::iterator I=CE.begin(), E=CE.end(); I!=E;++I)
Out << "\\l $" << I.getKey() << " : " << I.getData()->toString();
}
static void PrintNE(std::ostream& Out, ValueState* St) {
ValueState::ConstNotEqTy NE = St->ConstNotEq;
if (NE.isEmpty())
return;
Out << "\\l\\|'!=' constraints:";
for (ValueState::ConstNotEqTy::iterator I=NE.begin(), EI=NE.end();
I != EI; ++I){
Out << "\\l $" << I.getKey() << " : ";
bool isFirst = true;
ValueState::IntSetTy::iterator J=I.getData().begin(),
EJ=I.getData().end();
for ( ; J != EJ; ++J) {
if (isFirst) isFirst = false;
else Out << ", ";
Out << (*J)->toString();
}
}
}
static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) {
if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
GraphPrintCheckerState->isExplicitNullDeref(N) ||
Ted Kremenek
committed
GraphPrintCheckerState->isUndefDeref(N) ||
GraphPrintCheckerState->isUndefStore(N) ||
GraphPrintCheckerState->isUndefControlFlow(N) ||
GraphPrintCheckerState->isExplicitBadDivide(N) ||
GraphPrintCheckerState->isImplicitBadDivide(N) ||
Ted Kremenek
committed
GraphPrintCheckerState->isUndefResult(N) ||
GraphPrintCheckerState->isBadCall(N) ||
GraphPrintCheckerState->isUndefArg(N))
return "color=\"red\",style=\"filled\"";
Ted Kremenek
committed
if (GraphPrintCheckerState->isNoReturnCall(N))
return "color=\"blue\",style=\"filled\"";
return "";
}
static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) {
std::ostringstream Out;
Ted Kremenek
committed
// Program Location.
ProgramPoint Loc = N->getLocation();
switch (Loc.getKind()) {
case ProgramPoint::BlockEntranceKind:
Out << "Block Entrance: B"
<< cast<BlockEntrance>(Loc).getBlock()->getBlockID();
break;
case ProgramPoint::BlockExitKind:
assert (false);
break;
case ProgramPoint::PostStmtKind: {
Ted Kremenek
committed
const PostStmt& L = cast<PostStmt>(Loc);
Stmt* S = L.getStmt();
SourceLocation SLoc = S->getLocStart();
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
S->printPretty(Out);
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getLineNumber(SLoc) << " col="
<< GraphPrintSourceManager->getColumnNumber(SLoc) << "\\l";
}
Ted Kremenek
committed
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";
Ted Kremenek
committed
else if (GraphPrintCheckerState->isExplicitNullDeref(N))
Ted Kremenek
committed
Out << "\\|Explicit-Null Dereference.\\l";
Ted Kremenek
committed
else if (GraphPrintCheckerState->isUndefDeref(N))
Ted Kremenek
committed
Out << "\\|Dereference of undefialied value.\\l";
Ted Kremenek
committed
else if (GraphPrintCheckerState->isUndefStore(N))
Ted Kremenek
committed
Out << "\\|Store to Undefined LVal.";
else if (GraphPrintCheckerState->isExplicitBadDivide(N))
Out << "\\|Explicit divide-by zero or undefined value.";
else if (GraphPrintCheckerState->isImplicitBadDivide(N))
Out << "\\|Implicit divide-by zero or undefined value.";
Ted Kremenek
committed
else if (GraphPrintCheckerState->isUndefResult(N))
Ted Kremenek
committed
Out << "\\|Result of operation is undefined.";
else if (GraphPrintCheckerState->isNoReturnCall(N))
Out << "\\|Call to function marked \"noreturn\".";
Ted Kremenek
committed
else if (GraphPrintCheckerState->isBadCall(N))
Out << "\\|Call to NULL/Undefined.";
else if (GraphPrintCheckerState->isUndefArg(N))
Out << "\\|Argument in call is undefined";
break;
}
default: {
const BlockEdge& E = cast<BlockEdge>(Loc);
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
<< E.getDst()->getBlockID() << ')';
if (Stmt* T = E.getSrc()->getTerminator()) {
Ted Kremenek
committed
SourceLocation SLoc = T->getLocStart();
Out << "\\|Terminator: ";
Ted Kremenek
committed
E.getSrc()->printTerminator(Out);
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getLineNumber(SLoc) << " col="
<< GraphPrintSourceManager->getColumnNumber(SLoc);
}
Ted Kremenek
committed
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
if (isa<SwitchStmt>(T)) {
Stmt* Label = E.getDst()->getLabel();
if (Label) {
if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
C->getLHS()->printPretty(Out);
if (Stmt* RHS = C->getRHS()) {
Out << " .. ";
RHS->printPretty(Out);
}
Out << ":";
}
else {
assert (isa<DefaultStmt>(Label));
Out << "\\ldefault:";
}
}
else
Out << "\\l(implicit) default:";
}
else if (isa<IndirectGotoStmt>(T)) {
// FIXME
}
else {
Out << "\\lCondition: ";
if (*E.getSrc()->succ_begin() == E.getDst())
Out << "true";
else
Out << "false";
}
Out << "\\l";
}
Ted Kremenek
committed
if (GraphPrintCheckerState->isUndefControlFlow(N)) {
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
}
}
Out << "\\|StateID: " << (void*) N->getState() << "\\|";
Ted Kremenek
committed
N->getState()->printDOT(Out, GraphCheckerStatePrinter);
Ted Kremenek
committed
Out << "\\l";
return Out.str();
}
};
} // end llvm namespace
#endif
#ifndef NDEBUG
template <typename ITERATOR>
GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; }
template <>
GRExprEngine::NodeTy*
GetGraphNode<llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator>
(llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator I) {
return I->first;
}
template <typename ITERATOR>
static void AddSources(llvm::SmallVector<GRExprEngine::NodeTy*, 10>& Sources,
ITERATOR I, ITERATOR E) {
llvm::SmallPtrSet<void*,10> CachedSources;
for ( ; I != E; ++I ) {
GRExprEngine::NodeTy* N = GetGraphNode(I);
void* p = N->getLocation().getRawData();
if (CachedSources.count(p))
continue;
CachedSources.insert(p);
Sources.push_back(N);
}
}
#endif
void GRExprEngine::ViewGraph(bool trim) {
#ifndef NDEBUG
if (trim) {
llvm::SmallVector<NodeTy*, 10> Src;
AddSources(Src, null_derefs_begin(), null_derefs_end());
AddSources(Src, undef_derefs_begin(), undef_derefs_end());
AddSources(Src, explicit_bad_divides_begin(), explicit_bad_divides_end());
AddSources(Src, undef_results_begin(), undef_results_end());
AddSources(Src, bad_calls_begin(), bad_calls_end());
AddSources(Src, undef_arg_begin(), undef_arg_end());
AddSources(Src, undef_branches_begin(), undef_branches_end());
ViewGraph(&Src[0], &Src[0]+Src.size());
}
else {
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
Ted Kremenek
committed
GraphCheckerStatePrinter = TF->getCheckerStatePrinter();
llvm::ViewGraph(*G.roots_begin(), "GRExprEngine");
GraphPrintCheckerState = NULL;
GraphPrintSourceManager = NULL;
Ted Kremenek
committed
GraphCheckerStatePrinter = NULL;
}
#endif
}
void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
Ted Kremenek
committed
GraphCheckerStatePrinter = TF->getCheckerStatePrinter();
GRExprEngine::GraphTy* TrimmedG = G.Trim(Beg, End);