"llvm/lib/git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "399add01d423800b4cf664f23b52d53dadd36fd5"
Newer
Older
Sebastian Redl
committed
NodeTy* Pred,
NodeSet& Dst) {
QualType T = Ex->getTypeOfArgument();
uint64_t amt;
if (Ex->isSizeOf()) {
if (T == getContext().VoidTy) {
// sizeof(void) == 1 byte.
amt = 1;
}
else if (!T.getTypePtr()->isConstantSizeType()) {
// FIXME: Add support for VLAs.
}
else if (T->isObjCInterfaceType()) {
// Some code tries to take the sizeof an ObjCInterfaceType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
Ted Kremenek
committed
return;
}
else {
// All other cases.
amt = getContext().getTypeSize(T) / 8;
}
else // Get alignment of the type.
amt = getContext().getTypeAlign(T) / 8;
BindExpr(GetState(Pred), Ex,
NonLoc::MakeVal(getBasicVals(), amt, Ex->getType())));
Ted Kremenek
committed
}
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
Zhongxing Xu
committed
NodeSet& Dst, bool asLValue) {
switch (U->getOpcode()) {
default:
break;
Ted Kremenek
committed
case UnaryOperator::Deref: {
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal location = GetSVal(St, Ex);
Zhongxing Xu
committed
if (asLValue)
Ted Kremenek
committed
EvalLoad(Dst, U, *I, St, location);
}
Ted Kremenek
committed
case UnaryOperator::Real: {
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
// FIXME: We don't have complex SValues yet.
Ted Kremenek
committed
if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown."
Dst.Add(*I);
continue;
}
// For all other types, UnaryOperator::Real is an identity operation.
assert (U->getType() == Ex->getType());
Ted Kremenek
committed
}
return;
}
case UnaryOperator::Imag: {
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
// FIXME: We don't have complex SValues yet.
Ted Kremenek
committed
if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown."
Dst.Add(*I);
continue;
}
// For all other types, UnaryOperator::Float returns 0.
assert (Ex->getType()->isIntegerType());
Zhongxing Xu
committed
SVal X = NonLoc::MakeVal(getBasicVals(), 0, Ex->getType());
Ted Kremenek
committed
}
return;
}
// FIXME: Just report "Unknown" for OffsetOf.
case UnaryOperator::OffsetOf:
Dst.Add(Pred);
return;
Zhongxing Xu
committed
case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
case UnaryOperator::Extension: {
// Unary "+" is a no-op, similar to a parentheses. We still have places
// where it may be a block-level expression, so we need to
// generate an extra node that just propagates the value of the
// subexpression.
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
return;
}
case UnaryOperator::AddrOf: {
Zhongxing Xu
committed
assert(!asLValue);
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Zhongxing Xu
committed
VisitLValue(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal V = GetSVal(St, Ex);
MakeNode(Dst, U, *I, St);
}
return;
}
case UnaryOperator::LNot:
case UnaryOperator::Minus:
case UnaryOperator::Not: {
Zhongxing Xu
committed
assert (!asLValue);
Expr* Ex = U->getSubExpr()->IgnoreParens();
NodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
Ted Kremenek
committed
// Get the value of the subexpression.
Zhongxing Xu
committed
SVal V = GetSVal(St, Ex);
Ted Kremenek
committed
if (V.isUnknownOrUndef()) {
MakeNode(Dst, U, *I, BindExpr(St, U, V));
continue;
}
// QualType DstT = getContext().getCanonicalType(U->getType());
// QualType SrcT = getContext().getCanonicalType(Ex->getType());
//
// if (DstT != SrcT) // Perform promotions.
// V = EvalCast(V, DstT);
//
// if (V.isUnknownOrUndef()) {
// MakeNode(Dst, U, *I, BindExpr(St, U, V));
// continue;
// }
switch (U->getOpcode()) {
default:
assert(false && "Invalid Opcode.");
break;
case UnaryOperator::Not:
Ted Kremenek
committed
// FIXME: Do we need to handle promotions?
break;
case UnaryOperator::Minus:
Ted Kremenek
committed
// FIXME: Do we need to handle promotions?
break;
case UnaryOperator::LNot:
// C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
//
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
Zhongxing Xu
committed
if (isa<Loc>(V)) {
loc::ConcreteInt X(getBasicVals().getZeroWithPtrWidth());
SVal Result = EvalBinOp(BinaryOperator::EQ, cast<Loc>(V), X);
}
else {
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
Ted Kremenek
committed
#if 0
Zhongxing Xu
committed
SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
St = SetSVal(St, U, Result);
Ted Kremenek
committed
#else
Zhongxing Xu
committed
EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I);
Ted Kremenek
committed
continue;
#endif
}
break;
}
MakeNode(Dst, U, *I, St);
}
return;
}
}
Ted Kremenek
committed
// Handle ++ and -- (both pre- and post-increment).
Ted Kremenek
committed
assert (U->isIncrementDecrementOp());
NodeSet Tmp;
Expr* Ex = U->getSubExpr()->IgnoreParens();
Zhongxing Xu
committed
VisitLValue(Ex, Pred, Tmp);
for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
Zhongxing Xu
committed
SVal V1 = GetSVal(St, Ex);
// Perform a load.
NodeSet Tmp2;
EvalLoad(Tmp2, Ex, *I, St, V1);
for (NodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
St = GetState(*I2);
Zhongxing Xu
committed
SVal V2 = GetSVal(St, Ex);
// Propagate unknown and undefined values.
if (V2.isUnknownOrUndef()) {
continue;
}
Ted Kremenek
committed
// Handle all other values.
Ted Kremenek
committed
BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
: BinaryOperator::Sub;
Ted Kremenek
committed
Zhongxing Xu
committed
SVal Result = EvalBinOp(Op, V2, MakeConstantVal(1U, U));
// Perform the store.
EvalStore(Dst, U, *I2, St, V1, Result);
Ted Kremenek
committed
}
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;
Zhongxing Xu
committed
VisitLValue(*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
Zhongxing Xu
committed
// should evaluate to Locs. 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.
for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
Zhongxing Xu
committed
SVal X = GetSVal(St, *OI);
assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
Zhongxing Xu
committed
if (isa<Loc>(X))
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);
}
Ted Kremenek
committed
void GRExprEngine::EvalReturn(NodeSet& Dst, ReturnStmt* S, NodeTy* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
Ted Kremenek
committed
getTF().EvalReturn(Dst, *this, *Builder, S, Pred);
Ted Kremenek
committed
// Handle the case where no nodes where generated.
Ted Kremenek
committed
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
Ted Kremenek
committed
MakeNode(Dst, S, Pred, GetState(Pred));
}
void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {
Expr* R = S->getRetValue();
if (!R) {
Ted Kremenek
committed
EvalReturn(Dst, S, Pred);
return;
}
Ted Kremenek
committed
NodeSet Tmp;
Visit(R, Pred, Tmp);
Ted Kremenek
committed
for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
SVal X = GetSVal((*I)->getState(), R);
// Check if we return the address of a stack variable.
if (isa<loc::MemRegionVal>(X)) {
// Determine if the value is on the stack.
const MemRegion* R = cast<loc::MemRegionVal>(&X)->getRegion();
if (R && getStateManager().hasStackStorage(R)) {
// Create a special node representing the error.
if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) {
N->markAsSink();
RetsStackAddr.insert(N);
}
}
}
// Check if we return an undefined value.
else if (X.isUndef()) {
if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) {
N->markAsSink();
RetsUndef.insert(N);
}
continue;
}
Ted Kremenek
committed
EvalReturn(Dst, S, *I);
}
//===----------------------------------------------------------------------===//
// Transfer functions: Binary operators.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
const GRState* GRExprEngine::CheckDivideZero(Expr* Ex, const GRState* St,
NodeTy* Pred, SVal Denom) {
// Divide by undefined? (potentially zero)
if (Denom.isUndef()) {
NodeTy* DivUndef = Builder->generateNode(Ex, St, Pred);
if (DivUndef) {
DivUndef->markAsSink();
ExplicitBadDivides.insert(DivUndef);
}
Ted Kremenek
committed
return 0;
}
// Check for divide/remainder-by-zero.
// First, "assume" that the denominator is 0 or undefined.
bool isFeasibleZero = false;
const GRState* ZeroSt = Assume(St, Denom, false, isFeasibleZero);
// Second, "assume" that the denominator cannot be 0.
bool isFeasibleNotZero = false;
St = Assume(St, Denom, true, isFeasibleNotZero);
// Create the node for the divide-by-zero (if it occurred).
if (isFeasibleZero)
if (NodeTy* DivZeroNode = Builder->generateNode(Ex, ZeroSt, Pred)) {
DivZeroNode->markAsSink();
if (isFeasibleNotZero)
ImplicitBadDivides.insert(DivZeroNode);
else
ExplicitBadDivides.insert(DivZeroNode);
}
Ted Kremenek
committed
return isFeasibleNotZero ? St : 0;
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
GRExprEngine::NodeTy* Pred,
GRExprEngine::NodeSet& Dst) {
NodeSet Tmp1;
Expr* LHS = B->getLHS()->IgnoreParens();
Expr* RHS = B->getRHS()->IgnoreParens();
Ted Kremenek
committed
// FIXME: Add proper support for ObjCKVCRefExpr.
if (isa<ObjCKVCRefExpr>(LHS)) {
Visit(RHS, Pred, Dst);
return;
}
Zhongxing Xu
committed
VisitLValue(LHS, Pred, Tmp1);
Visit(LHS, Pred, Tmp1);
for (NodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1 != E1; ++I1) {
Zhongxing Xu
committed
SVal LeftV = GetSVal((*I1)->getState(), LHS);
// Process the RHS.
NodeSet Tmp2;
Visit(RHS, *I1, Tmp2);
// With both the LHS and RHS evaluated, process the operation itself.
for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2 != E2; ++I2) {
Ted Kremenek
committed
const GRState* OldSt = St;
Zhongxing Xu
committed
SVal RightV = GetSVal(St, RHS);
BinaryOperator::Opcode Op = B->getOpcode();
switch (Op) {
Ted Kremenek
committed
case BinaryOperator::Assign: {
Ted Kremenek
committed
// EXPERIMENTAL: "Conjured" symbols.
Ted Kremenek
committed
// FIXME: Handle structs.
QualType T = RHS->getType();
Ted Kremenek
committed
Ted Kremenek
committed
if (RightV.isUnknown() && (Loc::IsLocType(T) ||
(T->isScalarType() && T->isIntegerType()))) {
Ted Kremenek
committed
unsigned Count = Builder->getCurrentBlockCount();
Ted Kremenek
committed
SymbolRef Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
Ted Kremenek
committed
Ted Kremenek
committed
RightV = Loc::IsLocType(T)
Zhongxing Xu
committed
? cast<SVal>(loc::SymbolVal(Sym))
: cast<SVal>(nonloc::SymbolVal(Sym));
Ted Kremenek
committed
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
Ted Kremenek
committed
EvalStore(Dst, B, LHS, *I2, BindExpr(St, B, RightV), LeftV, RightV);
Ted Kremenek
committed
continue;
Ted Kremenek
committed
}
case BinaryOperator::Div:
case BinaryOperator::Rem:
Ted Kremenek
committed
// Special checking for integer denominators.
Ted Kremenek
committed
if (RHS->getType()->isIntegerType() &&
RHS->getType()->isScalarType()) {
Ted Kremenek
committed
St = CheckDivideZero(B, St, *I2, RightV);
if (!St) continue;
}
// FALL-THROUGH.
default: {
if (B->isAssignmentOp())
break;
// Process non-assignements except commas or short-circuited
// logical expressions (LAnd and LOr).
Zhongxing Xu
committed
SVal Result = EvalBinOp(Op, LeftV, RightV);
if (Result.isUnknown()) {
Ted Kremenek
committed
if (OldSt != St) {
// Generate a new node if we have already created a new state.
MakeNode(Dst, B, *I2, St);
}
else
Dst.Add(*I2);
continue;
}
if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
// The operands were *not* undefined, but the result is undefined.
// This is a special node that should be flagged as an error.
if (NodeTy* UndefNode = Builder->generateNode(B, St, *I2)) {
UndefNode->markAsSink();
UndefResults.insert(UndefNode);
}
continue;
}
// Otherwise, create a new node.
continue;
}
}
assert (B->isCompoundAssignmentOp());
if (Op >= BinaryOperator::AndAssign) {
Op = (BinaryOperator::Opcode) (Op - (BinaryOperator::AndAssign -
BinaryOperator::And));
}
else {
Op = (BinaryOperator::Opcode) (Op - BinaryOperator::MulAssign);
}
// Perform a load (the LHS). This performs the checks for
// null dereferences, and so on.
NodeSet Tmp3;
Zhongxing Xu
committed
SVal location = GetSVal(St, LHS);
EvalLoad(Tmp3, LHS, *I2, St, location);
for (NodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) {
St = GetState(*I3);
Zhongxing Xu
committed
SVal V = GetSVal(St, LHS);
Ted Kremenek
committed
// Check for divide-by-zero.
if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
Ted Kremenek
committed
&& RHS->getType()->isIntegerType()
&& RHS->getType()->isScalarType()) {
Ted Kremenek
committed
// CheckDivideZero returns a new state where the denominator
// is assumed to be non-zero.
St = CheckDivideZero(B, St, *I3, RightV);
if (!St)
continue;
}
// Propagate undefined values (left-side).
if (V.isUndef()) {
continue;
}
// Propagate unknown values (left and right-side).
if (RightV.isUnknown() || V.isUnknown()) {
EvalStore(Dst, B, LHS, *I3, BindExpr(St, B, UnknownVal()), location,
UnknownVal());
continue;
}
// At this point:
//
// The LHS is not Undef/Unknown.
// The RHS is not Unknown.
// Get the computation type.
QualType CTy = cast<CompoundAssignOperator>(B)->getComputationType();
CTy = getContext().getCanonicalType(CTy);
QualType LTy = getContext().getCanonicalType(LHS->getType());
QualType RTy = getContext().getCanonicalType(RHS->getType());
// Perform promotions.
if (LTy != CTy) V = EvalCast(V, CTy);
if (RTy != CTy) RightV = EvalCast(RightV, CTy);
// Evaluate operands and promote to result type.
Ted Kremenek
committed
if (RightV.isUndef()) {
Ted Kremenek
committed
// Propagate undefined values (right-side).
EvalStore(Dst,B, LHS, *I3, BindExpr(St, B, RightV), location, RightV);
continue;
}
Zhongxing Xu
committed
SVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType());
if (Result.isUndef()) {
// The operands were not undefined, but the result is undefined.
if (NodeTy* UndefNode = Builder->generateNode(B, St, *I3)) {
UndefNode->markAsSink();
UndefResults.insert(UndefNode);
Ted Kremenek
committed
}
Ted Kremenek
committed
continue;
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
if (Result.isUnknown() && (Loc::IsLocType(CTy)
|| (CTy->isScalarType() && CTy->isIntegerType()))) {
unsigned Count = Builder->getCurrentBlockCount();
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
// LValue on the LHS will bind to.
Ted Kremenek
committed
SymbolRef Sym = SymMgr.getConjuredSymbol(B->getRHS(), LTy, Count);
? cast<SVal>(loc::SymbolVal(Sym))
// However, we need to convert the symbol to the computation type.
Result = (LTy == CTy) ? LHSVal : EvalCast(LHSVal,CTy);
}
else {
// The left-hand side may bind to a different value then the
// computation type.
LHSVal = (LTy == CTy) ? Result : EvalCast(Result,LTy);
}
EvalStore(Dst, B, LHS, *I3, BindExpr(St, B, Result), location, LHSVal);
Ted Kremenek
committed
}
}
}
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Transfer-function Helpers.
//===----------------------------------------------------------------------===//
void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
Ted Kremenek
committed
BinaryOperator::Opcode Op,
Zhongxing Xu
committed
NonLoc L, NonLoc R,
Ted Kremenek
committed
Ted Kremenek
committed
EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R);
for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I)
Ted Kremenek
committed
MakeNode(Dst, Ex, Pred, *I);
}
void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* St,
Ted Kremenek
committed
Expr* Ex, BinaryOperator::Opcode Op,
Zhongxing Xu
committed
NonLoc L, NonLoc R) {
Ted Kremenek
committed
if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, St, Ex, Op, L, R);
Ted Kremenek
committed
}
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
#ifndef NDEBUG
static GRExprEngine* GraphPrintCheckerState;
Ted Kremenek
committed
static SourceManager* GraphPrintSourceManager;
namespace llvm {
template<>
struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
public DefaultDOTGraphTraits {
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;
default: {
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
if (isa<PostStmt>(Loc)) {
const PostStmt& L = cast<PostStmt>(Loc);
Stmt* S = L.getStmt();
SourceLocation SLoc = S->getLocStart();
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
llvm::raw_os_ostream OutS(Out);
S->printPretty(OutS);
OutS.flush();
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getLineNumber(SLoc) << " col="
<< GraphPrintSourceManager->getColumnNumber(SLoc) << "\\l";
}
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";
else if (GraphPrintCheckerState->isExplicitNullDeref(N))
Out << "\\|Explicit-Null Dereference.\\l";
else if (GraphPrintCheckerState->isUndefDeref(N))
Out << "\\|Dereference of undefialied value.\\l";
else if (GraphPrintCheckerState->isUndefStore(N))
Out << "\\|Store to Undefined Loc.";
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.";
else if (GraphPrintCheckerState->isUndefResult(N))
Out << "\\|Result of operation is undefined.";
else if (GraphPrintCheckerState->isNoReturnCall(N))
Out << "\\|Call to function marked \"noreturn\".";
else if (GraphPrintCheckerState->isBadCall(N))
Out << "\\|Call to NULL/Undefined.";
else if (GraphPrintCheckerState->isUndefArg(N))
Out << "\\|Argument in call is undefined";
break;
}
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
llvm::raw_os_ostream OutS(Out);
E.getSrc()->printTerminator(OutS);
OutS.flush();
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getLineNumber(SLoc) << " col="
<< GraphPrintSourceManager->getColumnNumber(SLoc);
}
Ted Kremenek
committed
if (isa<SwitchStmt>(T)) {
Stmt* Label = E.getDst()->getLabel();
if (Label) {
if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
llvm::raw_os_ostream OutS(Out);
C->getLHS()->printPretty(OutS);
OutS.flush();
if (Stmt* RHS = C->getRHS()) {
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() << "\\|";
GRStateRef state(N->getState(), GraphPrintCheckerState->getStateManager());
state.printDOT(Out);
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(std::vector<GRExprEngine::NodeTy*>& Sources,
ITERATOR I, ITERATOR E) {
Ted Kremenek
committed
llvm::SmallSet<ProgramPoint,10> CachedSources;
for ( ; I != E; ++I ) {
GRExprEngine::NodeTy* N = GetGraphNode(I);
Ted Kremenek
committed
ProgramPoint P = N->getLocation();
Ted Kremenek
committed
if (CachedSources.count(P))
continue;
Ted Kremenek
committed
CachedSources.insert(P);
Sources.push_back(N);
}
}
#endif
void GRExprEngine::ViewGraph(bool trim) {
#ifndef NDEBUG
if (trim) {
std::vector<NodeTy*> Src;
// Fixme: Migrate over to the new way of adding nodes.
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());
// The new way.
for (BugTypeSet::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
(*I)->GetErrorNodes(Src);
ViewGraph(&Src[0], &Src[0]+Src.size());
}
else {
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
llvm::ViewGraph(*G.roots_begin(), "GRExprEngine");
GraphPrintCheckerState = NULL;
GraphPrintSourceManager = NULL;
}
#endif
}
void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
GRExprEngine::GraphTy* TrimmedG = G.Trim(Beg, End);
if (!TrimmedG)
llvm::cerr << "warning: Trimmed ExplodedGraph is empty.\n";
else {
llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine");
delete TrimmedG;
}
GraphPrintCheckerState = NULL;
Ted Kremenek
committed
GraphPrintSourceManager = NULL;