Newer
Older
// 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();
if (B->isAssignmentOp())
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() && (T->isIntegerType() || Loc::IsLocType(T))) {
Ted Kremenek
committed
unsigned Count = Builder->getCurrentBlockCount();
SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
Zhongxing Xu
committed
RightV = Loc::IsLocType(B->getRHS()->getType())
? 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
Zhongxing Xu
committed
EvalStore(Dst, B, LHS, *I2, SetSVal(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.
if (RHS->getType()->isIntegerType()) {
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.
Zhongxing Xu
committed
MakeNode(Dst, B, *I2, SetSVal(St, B, Result));
continue;
}
}
assert (B->isCompoundAssignmentOp());
if (Op >= BinaryOperator::AndAssign)
((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And);
else
((int&) 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)
&& RHS->getType()->isIntegerType()) {
// 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()) {
Zhongxing Xu
committed
EvalStore(Dst, B, LHS, *I3, SetSVal(St, B, V), location, V);
continue;
}
// Propagate unknown values (left and right-side).
if (RightV.isUnknown() || V.isUnknown()) {
Zhongxing Xu
committed
EvalStore(Dst, B, LHS, *I3, SetSVal(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();
// Perform promotions.
V = EvalCast(V, 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).
Zhongxing Xu
committed
EvalStore(Dst, B, LHS, *I3, SetSVal(St, B, RightV), location, RightV);
continue;
}
// Compute the result of the operation.
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.
Ted Kremenek
committed
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() &&
(CTy->isIntegerType() || Loc::IsLocType(CTy))) {
unsigned Count = Builder->getCurrentBlockCount();
SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
Result = Loc::IsLocType(CTy)
? cast<SVal>(loc::SymbolVal(Sym))
: cast<SVal>(nonloc::SymbolVal(Sym));
}
Zhongxing Xu
committed
EvalStore(Dst, B, LHS, *I3, SetSVal(St, B, Result), location, Result);
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
Ted Kremenek
committed
if (R.isValid()) getTF().EvalBinOpNN(OStates, StateMgr, 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;
case ProgramPoint::PostLoadKind:
case ProgramPoint::PostPurgeDeadSymbolsKind:
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 << ' ';
llvm::raw_os_ostream OutS(Out);
S->printPretty(OutS);
OutS.flush();
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))
Zhongxing Xu
committed
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.";
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
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;