//=-- 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" GRExprEngine::StateTy GRExprEngine::SetValue(StateTy St, Expr* S, const RValue& V) { if (!StateCleaned) { St = RemoveDeadBindings(CurrentStmt, St); StateCleaned = true; } bool isBlkExpr = false; if (S == CurrentStmt) { isBlkExpr = getCFG().isBlkExpr(S); if (!isBlkExpr) return St; } return StateMgr.SetValue(St, S, isBlkExpr, V); } const GRExprEngine::StateTy::BufferTy& GRExprEngine::SetValue(StateTy St, Expr* S, const RValue::BufferTy& RB, StateTy::BufferTy& RetBuf) { assert (RetBuf.empty()); for (RValue::BufferTy::const_iterator I=RB.begin(), E=RB.end(); I!=E; ++I) RetBuf.push_back(SetValue(St, S, *I)); return RetBuf; } GRExprEngine::StateTy GRExprEngine::SetValue(StateTy St, const LValue& LV, const RValue& V) { if (LV.isUnknown()) return St; if (!StateCleaned) { St = RemoveDeadBindings(CurrentStmt, St); StateCleaned = true; } return StateMgr.SetValue(St, LV, V); } void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term, BranchNodeBuilder& builder) { // Remove old bindings for subexpressions. StateTy PrevState = StateMgr.RemoveSubExprBindings(builder.getState()); RValue V = GetValue(PrevState, Condition); switch (V.getBaseKind()) { default: break; case RValue::UnknownKind: builder.generateNode(PrevState, true); builder.generateNode(PrevState, false); return; case RValue::UninitializedKind: { NodeTy* N = builder.generateNode(PrevState, true); if (N) { N->markAsSink(); UninitBranches.insert(N); } builder.markInfeasible(false); return; } } // Get the current block counter. GRBlockCounter BC = builder.getBlockCounter(); unsigned BlockID = builder.getTargetBlock(true)->getBlockID(); unsigned NumVisited = BC.getNumVisited(BlockID); if (isa(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(St, true); else builder.markInfeasible(true); } else builder.markInfeasible(true); BlockID = builder.getTargetBlock(false)->getBlockID(); NumVisited = BC.getNumVisited(BlockID); if (isa(V) || BC.getNumVisited(builder.getTargetBlock(false)->getBlockID()) < 1) { // Process the false branch. bool isFeasible = false; StateTy St = Assume(PrevState, V, false, isFeasible); if (isFeasible) builder.generateNode(St, false); else builder.markInfeasible(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) { StateTy St = builder.getState(); LValue V = cast(GetValue(St, builder.getTarget())); // Three possibilities: // // (1) We know the computed label. // (2) The label is NULL (or some other constant), or Uninitialized. // (3) We have no clue about the label. Dispatch to all targets. // typedef IndirectGotoNodeBuilder::iterator iterator; if (isa(V)) { LabelStmt* L = cast(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; } if (isa(V) || isa(V)) { // Dispatch to the first target and mark it as a sink. NodeTy* N = builder.generateNode(builder.begin(), St, true); UninitBranches.insert(N); return; } // This is really a catch-all. We don't support symbolics yet. assert (isa(V)); for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) builder.generateNode(I, St); } /// 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; StateTy St = builder.getState(); NonLValue CondV = cast(GetValue(St, builder.getCondition())); if (isa(CondV)) { NodeTy* N = builder.generateDefaultCaseNode(St, true); UninitBranches.insert(N); return; } StateTy 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(getContext().IntTy,SourceLocation()); APSInt V1(bits, false); APSInt V2 = V1; for (iterator I=builder.begin(), E=builder.end(); I!=E; ++I) { CaseStmt* Case = cast(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 NonLValues. do { nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1)); NonLValue Res = EvalBinaryOp(ValMgr, BinaryOperator::EQ, CondV, CaseVal); // Now "assume" that the case matches. bool isFeasible; StateTy 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(CondV)) return; } // Now "assume" that the case doesn't match. Add this state // to the default state (if it is feasible). StNew = Assume(DefaultSt, Res, false, isFeasible); if (isFeasible) DefaultSt = StNew; // Concretize the next value in the range. ++V1; } while (V1 < V2); } // If we reach here, than we know that the default branch is // possible. builder.generateDefaultCaseNode(DefaultSt); } void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst) { bool hasR2; StateTy PrevState = Pred->getState(); RValue R1 = GetValue(PrevState, B->getLHS()); RValue R2 = GetValue(PrevState, B->getRHS(), hasR2); if (isa(R1) && (isa(R2) || isa(R2))) { Nodify(Dst, B, Pred, SetValue(PrevState, B, R2)); return; } else if (isa(R1)) { Nodify(Dst, B, Pred, SetValue(PrevState, B, R1)); return; } // R1 is an expression that can evaluate to either 'true' or 'false'. if (B->getOpcode() == BinaryOperator::LAnd) { // hasR2 == 'false' means that LHS evaluated to 'false' and that // we short-circuited, leading to a value of '0' for the '&&' expression. if (hasR2 == false) { Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(0U, B))); return; } } else { assert (B->getOpcode() == BinaryOperator::LOr); // hasR2 == 'false' means that the LHS evaluate to 'true' and that // we short-circuited, leading to a value of '1' for the '||' expression. if (hasR2 == false) { Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(1U, B))); return; } } // If we reach here we did not short-circuit. Assume R2 == true and // R2 == false. bool isFeasible; StateTy St = Assume(PrevState, R2, true, isFeasible); if (isFeasible) Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(1U, B))); St = Assume(PrevState, R2, false, isFeasible); if (isFeasible) Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(0U, B))); } void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { Builder = &builder; StmtEntryNode = builder.getLastNode(); CurrentStmt = S; NodeSet Dst; StateCleaned = false; Visit(S, StmtEntryNode, Dst); // If no nodes were generated, generate a new node that has all the // dead mappings removed. if (Dst.size() == 1 && *Dst.begin() == StmtEntryNode) { StateTy St = RemoveDeadBindings(S, StmtEntryNode->getState()); builder.generateNode(S, St, StmtEntryNode); } CurrentStmt = NULL; StmtEntryNode = NULL; Builder = NULL; } GRExprEngine::NodeTy* GRExprEngine::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St) { // If the state hasn't changed, don't generate a new node. if (St == Pred->getState()) return NULL; NodeTy* N = Builder->generateNode(S, St, Pred); Dst.Add(N); return N; } void GRExprEngine::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, const StateTy::BufferTy& SB) { for (StateTy::BufferTy::const_iterator I=SB.begin(), E=SB.end(); I!=E; ++I) Nodify(Dst, S, Pred, *I); } void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ if (D != CurrentStmt) { Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. return; } // If we are here, we are loading the value of the decl and binding // it to the block-level expression. StateTy St = Pred->getState(); Nodify(Dst, D, Pred, SetValue(St, D, GetValue(St, lval::DeclVal(D->getDecl())))); } void GRExprEngine::VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst) { QualType T = CastE->getType(); // Check for redundant casts. if (E->getType() == T) { Dst.Add(Pred); return; } NodeSet S1; Visit(E, Pred, S1); for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { NodeTy* N = *I1; StateTy St = N->getState(); const RValue& V = GetValue(St, E); Nodify(Dst, CastE, N, SetValue(St, CastE, EvalCast(ValMgr, V, CastE))); } } void GRExprEngine::VisitDeclStmt(DeclStmt* DS, GRExprEngine::NodeTy* Pred, GRExprEngine::NodeSet& Dst) { StateTy St = Pred->getState(); for (const ScopedDecl* D = DS->getDecl(); D; D = D->getNextDeclarator()) if (const VarDecl* VD = dyn_cast(D)) { const Expr* E = VD->getInit(); St = SetValue(St, lval::DeclVal(VD), E ? GetValue(St, E) : UninitializedVal()); } Nodify(Dst, DS, Pred, St); if (Dst.empty()) Dst.Add(Pred); } void GRExprEngine::VisitGuardedExpr(Expr* S, Expr* LHS, Expr* RHS, NodeTy* Pred, NodeSet& Dst) { StateTy St = Pred->getState(); RValue R = GetValue(St, LHS); if (isa(R)) R = GetValue(St, RHS); Nodify(Dst, S, Pred, SetValue(St, S, R)); } /// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type). void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* S, NodeTy* Pred, NodeSet& Dst) { // 6.5.3.4 sizeof: "The result type is an integer." QualType T = S->getArgumentType(); // FIXME: Add support for VLAs. if (isa(T.getTypePtr())) return; SourceLocation L = S->getExprLoc(); uint64_t size = getContext().getTypeSize(T, L) / 8; Nodify(Dst, S, Pred, SetValue(Pred->getState(), S, NonLValue::GetValue(ValMgr, size, getContext().IntTy, L))); } void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, GRExprEngine::NodeTy* Pred, GRExprEngine::NodeSet& Dst) { NodeSet S1; UnaryOperator::Opcode Op = U->getOpcode(); // FIXME: This is a hack so that for '*' and '&' we don't recurse // on visiting the subexpression if it is a DeclRefExpr. We should // probably just handle AddrOf and Deref in their own methods to make // this cleaner. if ((Op == UnaryOperator::Deref || Op == UnaryOperator::AddrOf) && isa(U->getSubExpr())) S1.Add(Pred); else Visit(U->getSubExpr(), Pred, S1); for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { NodeTy* N1 = *I1; StateTy St = N1->getState(); switch (U->getOpcode()) { case UnaryOperator::PostInc: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue Result = EvalBinaryOp(ValMgr, BinaryOperator::Add, R1, GetRValueConstant(1U, U)); Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result)); break; } case UnaryOperator::PostDec: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue Result = EvalBinaryOp(ValMgr, BinaryOperator::Sub, R1, GetRValueConstant(1U, U)); Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result)); break; } case UnaryOperator::PreInc: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue Result = EvalBinaryOp(ValMgr, BinaryOperator::Add, R1, GetRValueConstant(1U, U)); Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result)); break; } case UnaryOperator::PreDec: { const LValue& L1 = GetLValue(St, U->getSubExpr()); NonLValue R1 = cast(GetValue(St, L1)); NonLValue Result = EvalBinaryOp(ValMgr, BinaryOperator::Sub, R1, GetRValueConstant(1U, U)); Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result)); break; } case UnaryOperator::Minus: { const NonLValue& R1 = cast(GetValue(St, U->getSubExpr())); Nodify(Dst, U, N1, SetValue(St, U, EvalMinus(ValMgr, U, R1))); break; } case UnaryOperator::Not: { const NonLValue& R1 = cast(GetValue(St, U->getSubExpr())); Nodify(Dst, U, N1, SetValue(St, U, EvalComplement(ValMgr, R1))); 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". RValue V1 = GetValue(St, U->getSubExpr()); if (isa(V1)) { const LValue& L1 = cast(V1); lval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth()); Nodify(Dst, U, N1, SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ, L1, V2))); } else { const NonLValue& R1 = cast(V1); nonlval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth()); Nodify(Dst, U, N1, SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ, R1, V2))); } break; } case UnaryOperator::SizeOf: { // 6.5.3.4 sizeof: "The result type is an integer." QualType T = U->getSubExpr()->getType(); // FIXME: Add support for VLAs. if (isa(T.getTypePtr())) return; SourceLocation L = U->getExprLoc(); uint64_t size = getContext().getTypeSize(T, L) / 8; Nodify(Dst, U, N1, SetValue(St, U, NonLValue::GetValue(ValMgr, size, getContext().IntTy, L))); break; } case UnaryOperator::AddrOf: { const LValue& L1 = GetLValue(St, U->getSubExpr()); Nodify(Dst, U, N1, SetValue(St, U, L1)); break; } case UnaryOperator::Deref: { // FIXME: Stop when dereferencing an uninitialized value. // FIXME: Bifurcate when dereferencing a symbolic with no constraints? const RValue& V = GetValue(St, U->getSubExpr()); const LValue& L1 = cast(V); // After a dereference, one of two possible situations arise: // (1) A crash, because the pointer was NULL. // (2) The pointer is not NULL, and the dereference works. // // We add these assumptions. bool isFeasibleNotNull; // "Assume" that the pointer is Not-NULL. StateTy StNotNull = Assume(St, L1, true, isFeasibleNotNull); if (isFeasibleNotNull) { QualType T = U->getType(); Nodify(Dst, U, N1, SetValue(StNotNull, U, GetValue(StNotNull, L1, &T))); } bool isFeasibleNull; // "Assume" that the pointer is NULL. StateTy StNull = Assume(St, L1, false, isFeasibleNull); if (isFeasibleNull) { // We don't use "Nodify" here because the node will be a sink // and we have no intention of processing it later. NodeTy* NullNode = Builder->generateNode(U, StNull, N1); if (NullNode) { NullNode->markAsSink(); if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode); else ExplicitNullDeref.insert(NullNode); } } break; } default: ; assert (false && "Not implemented."); } } } void GRExprEngine::VisitAssignmentLHS(Expr* E, GRExprEngine::NodeTy* Pred, GRExprEngine::NodeSet& Dst) { if (isa(E)) { Dst.Add(Pred); return; } if (UnaryOperator* U = dyn_cast(E)) { if (U->getOpcode() == UnaryOperator::Deref) { Visit(U->getSubExpr(), Pred, Dst); return; } } Visit(E, Pred, Dst); } void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, GRExprEngine::NodeTy* Pred, GRExprEngine::NodeSet& Dst) { NodeSet S1; if (B->isAssignmentOp()) VisitAssignmentLHS(B->getLHS(), Pred, S1); else Visit(B->getLHS(), Pred, S1); for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { NodeTy* N1 = *I1; // 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 LValue, // so we use GetLValue instead of GetValue so that DeclRefExpr's are // evaluated to LValueDecl's instead of to an NonLValue. const RValue& V1 = B->isAssignmentOp() ? GetLValue(N1->getState(), B->getLHS()) : GetValue(N1->getState(), B->getLHS()); NodeSet S2; Visit(B->getRHS(), N1, S2); for (NodeSet::iterator I2=S2.begin(), E2=S2.end(); I2 != E2; ++I2) { NodeTy* N2 = *I2; StateTy St = N2->getState(); const RValue& V2 = GetValue(St, B->getRHS()); BinaryOperator::Opcode Op = B->getOpcode(); if (Op <= BinaryOperator::Or) { if (isa(V1) || isa(V1)) { Nodify(Dst, B, N2, SetValue(St, B, V1)); continue; } if (isa(V1)) { // FIXME: Add support for RHS being a non-lvalue. const LValue& L1 = cast(V1); const LValue& L2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(ValMgr, Op, L1, L2))); } else { const NonLValue& R1 = cast(V1); const NonLValue& R2 = cast(V2); Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(ValMgr, Op, R1, R2))); } continue; } switch (Op) { case BinaryOperator::Assign: { const LValue& L1 = cast(V1); Nodify(Dst, B, N2, SetValue(SetValue(St, B, V2), L1, V2)); break; } default: { // Compound assignment operators. assert (B->isCompoundAssignmentOp()); const LValue& L1 = cast(V1); RValue Result = cast(UnknownVal()); if (Op >= BinaryOperator::AndAssign) ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And); else ((int&) Op) -= BinaryOperator::MulAssign; if (isa(V2)) { // FIXME: Add support for Non-LValues on RHS. const LValue& L2 = cast(V2); Result = EvalBinaryOp(ValMgr, Op, L1, L2); } else { const NonLValue& R1 = cast(GetValue(N1->getState(), L1)); const NonLValue& R2 = cast(V2); Result = EvalBinaryOp(ValMgr, Op, R1, R2); } Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } } } } } void GRExprEngine::Visit(Stmt* S, GRExprEngine::NodeTy* Pred, GRExprEngine::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, CharacterLiteral, IntegerLiteral Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(S); if (B->isLogicalOp()) { VisitLogicalExpr(B, Pred, Dst); break; } else if (B->getOpcode() == BinaryOperator::Comma) { StateTy St = Pred->getState(); Nodify(Dst, B, Pred, SetValue(St, B, GetValue(St, B->getRHS()))); break; } VisitBinaryOperator(cast(S), Pred, Dst); break; } case Stmt::CastExprClass: { CastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst); break; } case Stmt::ChooseExprClass: { // __builtin_choose_expr ChooseExpr* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } case Stmt::CompoundAssignOperatorClass: VisitBinaryOperator(cast(S), Pred, Dst); break; case Stmt::ConditionalOperatorClass: { // '?' operator ConditionalOperator* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast(S), Pred, Dst); break; case Stmt::DeclStmtClass: VisitDeclStmt(cast(S), Pred, Dst); break; case Stmt::ImplicitCastExprClass: { ImplicitCastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst); break; } case Stmt::ParenExprClass: Visit(cast(S)->getSubExpr(), Pred, Dst); break; case Stmt::SizeOfAlignOfTypeExprClass: VisitSizeOfAlignOfTypeExpr(cast(S), Pred, Dst); break; case Stmt::StmtExprClass: { StmtExpr* SE = cast(S); StateTy St = Pred->getState(); Expr* LastExpr = cast(*SE->getSubStmt()->body_rbegin()); Nodify(Dst, SE, Pred, SetValue(St, SE, GetValue(St, LastExpr))); break; } case Stmt::ReturnStmtClass: { if (Expr* R = cast(S)->getRetValue()) Visit(R, Pred, Dst); else Dst.Add(Pred); break; } case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast(S), Pred, Dst); break; } } //===----------------------------------------------------------------------===// // "Assume" logic. //===----------------------------------------------------------------------===// GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, LValue Cond, bool Assumption, bool& isFeasible) { switch (Cond.getSubKind()) { default: assert (false && "'Assume' not implemented for this LValue."); return St; case lval::SymbolValKind: if (Assumption) return AssumeSymNE(St, cast(Cond).getSymbol(), ValMgr.getZeroWithPtrWidth(), isFeasible); else return AssumeSymEQ(St, cast(Cond).getSymbol(), ValMgr.getZeroWithPtrWidth(), isFeasible); case lval::DeclValKind: isFeasible = Assumption; return St; case lval::ConcreteIntKind: { bool b = cast(Cond).getValue() != 0; isFeasible = b ? Assumption : !Assumption; return St; } } } GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, NonLValue Cond, bool Assumption, bool& isFeasible) { switch (Cond.getSubKind()) { default: assert (false && "'Assume' not implemented for this NonLValue."); return St; case nonlval::SymbolValKind: { nonlval::SymbolVal& SV = cast(Cond); SymbolID sym = SV.getSymbol(); if (Assumption) return AssumeSymNE(St, sym, ValMgr.getValue(0, SymMgr.getType(sym)), isFeasible); else return AssumeSymEQ(St, sym, ValMgr.getValue(0, SymMgr.getType(sym)), isFeasible); } case nonlval::SymIntConstraintValKind: return AssumeSymInt(St, Assumption, cast(Cond).getConstraint(), isFeasible); case nonlval::ConcreteIntKind: { bool b = cast(Cond).getValue() != 0; isFeasible = b ? Assumption : !Assumption; return St; } } } GRExprEngine::StateTy GRExprEngine::AssumeSymNE(StateTy St, SymbolID sym, const llvm::APSInt& V, bool& isFeasible) { // First, determine if sym == X, where X != V. if (const llvm::APSInt* X = St.getSymVal(sym)) { isFeasible = *X != V; return St; } // Second, determine if sym != V. if (St.isNotEqual(sym, V)) { 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); } GRExprEngine::StateTy GRExprEngine::AssumeSymEQ(StateTy St, SymbolID sym, const llvm::APSInt& V, bool& isFeasible) { // First, determine if sym == X, where X != V. if (const llvm::APSInt* X = St.getSymVal(sym)) { isFeasible = *X == V; return St; } // Second, determine if sym != V. if (St.isNotEqual(sym, V)) { 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); } GRExprEngine::StateTy GRExprEngine::AssumeSymInt(StateTy St, bool Assumption, const SymIntConstraint& C, bool& isFeasible) { switch (C.getOpcode()) { default: // No logic yet for other operators. 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); } } //===----------------------------------------------------------------------===// // Driver. //===----------------------------------------------------------------------===// #ifndef NDEBUG static GRExprEngine* GraphPrintCheckerState; namespace llvm { template<> struct VISIBILITY_HIDDEN DOTGraphTraits : public DefaultDOTGraphTraits { static void PrintVarBindings(std::ostream& Out, GRExprEngine::StateTy St) { Out << "Variables:\\l"; bool isFirst = true; for (GRExprEngine::StateTy::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, GRExprEngine::StateTy St){ bool isFirst = true; for (GRExprEngine::StateTy::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, GRExprEngine::StateTy St){ bool isFirst = true; for (GRExprEngine::StateTy::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, GRExprEngine::StateTy St) { ValueState::ConstantEqTy CE = St.getImpl()->ConstantEq; if (CE.isEmpty()) return; Out << "\\l\\|'==' constraints:"; for (ValueState::ConstantEqTy::iterator I=CE.begin(), E=CE.end(); I!=E;++I) Out << "\\l $" << I.getKey() << " : " << I.getData()->toString(); } static void PrintNE(std::ostream& Out, GRExprEngine::StateTy St) { ValueState::ConstantNotEqTy NE = St.getImpl()->ConstantNotEq; if (NE.isEmpty()) return; Out << "\\l\\|'!=' constraints:"; for (ValueState::ConstantNotEqTy::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 getNodeLabel(const GRExprEngine::NodeTy* N, void*) { std::ostringstream Out; // Program Location. ProgramPoint Loc = N->getLocation(); switch (Loc.getKind()) { case ProgramPoint::BlockEntranceKind: Out << "Block Entrance: B" << cast(Loc).getBlock()->getBlockID(); break; case ProgramPoint::BlockExitKind: assert (false); break; case ProgramPoint::PostStmtKind: { const PostStmt& L = cast(Loc); Out << L.getStmt()->getStmtClassName() << ':' << (void*) L.getStmt() << ' '; L.getStmt()->printPretty(Out); if (GraphPrintCheckerState->isImplicitNullDeref(N)) { Out << "\\|Implicit-Null Dereference.\\l"; } else if (GraphPrintCheckerState->isExplicitNullDeref(N)) { Out << "\\|Explicit-Null Dereference.\\l"; } break; } default: { const BlockEdge& E = cast(Loc); Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; if (Stmt* T = E.getSrc()->getTerminator()) { Out << "\\|Terminator: "; E.getSrc()->printTerminator(Out); if (isa(T)) { Stmt* Label = E.getDst()->getLabel(); if (Label) { if (CaseStmt* C = dyn_cast(Label)) { Out << "\\lcase "; C->getLHS()->printPretty(Out); if (Stmt* RHS = C->getRHS()) { Out << " .. "; RHS->printPretty(Out); } Out << ":"; } else { assert (isa(Label)); Out << "\\ldefault:"; } } else Out << "\\l(implicit) default:"; } else if (isa(T)) { // FIXME } else { Out << "\\lCondition: "; if (*E.getSrc()->succ_begin() == E.getDst()) Out << "true"; else Out << "false"; } Out << "\\l"; } if (GraphPrintCheckerState->isUninitControlFlow(N)) { Out << "\\|Control-flow based on\\lUninitialized value.\\l"; } } } Out << "\\|StateID: " << (void*) N->getState().getImpl() << "\\|"; N->getState().printDOT(Out); Out << "\\l"; return Out.str(); } }; } // end llvm namespace #endif namespace clang { void RunGRConstants(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx, Diagnostic& Diag) { GRCoreEngine Engine(cfg, FD, Ctx); GRExprEngine* CheckerState = &Engine.getCheckerState(); GRSimpleVals GRSV; CheckerState->setTransferFunctions(GRSV); // Execute the worklist algorithm. Engine.ExecuteWorkList(); // Look for explicit-Null dereferences and warn about them. for (GRExprEngine::null_iterator I=CheckerState->null_begin(), E=CheckerState->null_end(); I!=E; ++I) { const PostStmt& L = cast((*I)->getLocation()); Expr* E = cast(L.getStmt()); Diag.Report(FullSourceLoc(E->getExprLoc(), Ctx.getSourceManager()), diag::chkr_null_deref_after_check); } #ifndef NDEBUG GraphPrintCheckerState = CheckerState; llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRExprEngine"); GraphPrintCheckerState = NULL; #endif } } // end clang namespace