Skip to content
GRExprEngine.cpp 92.3 KiB
Newer Older
                                          NodeTy* Pred,
                                          NodeSet& Dst) {
  QualType T = Ex->getTypeOfArgument();
    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.      
      amt = getContext().getTypeSize(T) / 8;
  }
  else  // Get alignment of the type.
    amt = getContext().getTypeAlign(T) / 8;
  MakeNode(Dst, Ex, Pred,
Zhongxing Xu's avatar
Zhongxing Xu committed
           BindExpr(GetState(Pred), Ex,
                    NonLoc::MakeVal(getBasicVals(), amt, Ex->getType())));  
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
    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) {
        const GRState* St = GetState(*I);
Zhongxing Xu's avatar
Zhongxing Xu committed
          MakeNode(Dst, U, *I, BindExpr(St, U, location));
    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) {
        
        // FIXME: We don't have complex SValues yet.
        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());
        const GRState* St = GetState(*I);
Zhongxing Xu's avatar
Zhongxing Xu committed
        MakeNode(Dst, U, *I, BindExpr(St, U, GetSVal(St, Ex)));
      } 
      
      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) {
        // FIXME: We don't have complex SValues yet.
        if (Ex->getType()->isAnyComplexType()) {
          // Just report "Unknown."
          Dst.Add(*I);
          continue;
        }
        
        // For all other types, UnaryOperator::Float returns 0.
        assert (Ex->getType()->isIntegerType());
        const GRState* St = GetState(*I);
        SVal X = NonLoc::MakeVal(getBasicVals(), 0, Ex->getType());
Zhongxing Xu's avatar
Zhongxing Xu committed
        MakeNode(Dst, U, *I, BindExpr(St, U, X));
    case UnaryOperator::OffsetOf:
      Dst.Add(Pred);
      return;
      
    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) {        
        const GRState* St = GetState(*I);
Zhongxing Xu's avatar
Zhongxing Xu committed
        MakeNode(Dst, U, *I, BindExpr(St, U, GetSVal(St, Ex)));
      Expr* Ex = U->getSubExpr()->IgnoreParens();
      NodeSet Tmp;
     
      for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {        
        const GRState* St = GetState(*I);
Zhongxing Xu's avatar
Zhongxing Xu committed
        St = BindExpr(St, U, V);
    case UnaryOperator::LNot:
    case UnaryOperator::Minus:
    case UnaryOperator::Not: {
      Expr* Ex = U->getSubExpr()->IgnoreParens();
      NodeSet Tmp;
      Visit(Ex, Pred, Tmp);
      for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {        
        const GRState* St = GetState(*I);
        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:
            // FIXME: Do we need to handle promotions?
Zhongxing Xu's avatar
Zhongxing Xu committed
            St = BindExpr(St, U, EvalComplement(cast<NonLoc>(V)));
            // FIXME: Do we need to handle promotions?
Zhongxing Xu's avatar
Zhongxing Xu committed
            St = BindExpr(St, U, EvalMinus(U, cast<NonLoc>(V)));
            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".
            
            if (isa<Loc>(V)) {
              loc::ConcreteInt X(getBasicVals().getZeroWithPtrWidth());
              SVal Result = EvalBinOp(BinaryOperator::EQ, cast<Loc>(V), X);
Zhongxing Xu's avatar
Zhongxing Xu committed
              St = BindExpr(St, U, Result);
              nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
              SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
              St = SetSVal(St, U, Result);
              EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I);
  // Handle ++ and -- (both pre- and post-increment).
  assert (U->isIncrementDecrementOp());
  NodeSet Tmp;
  Expr* Ex = U->getSubExpr()->IgnoreParens();
  for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
    
    const GRState* St = GetState(*I);
    
    // 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);
        
      // Propagate unknown and undefined values.      
      if (V2.isUnknownOrUndef()) {
Zhongxing Xu's avatar
Zhongxing Xu committed
        MakeNode(Dst, U, *I2, BindExpr(St, U, V2));
      BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
                                                     : BinaryOperator::Sub;
      SVal Result = EvalBinOp(Op, V2, MakeConstantVal(1U, U));      
Zhongxing Xu's avatar
Zhongxing Xu committed
      St = BindExpr(St, U, U->isPostfix() ? V2 : Result);
      EvalStore(Dst, U, *I2, St, V1, Result);
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;
  
  ++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 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.
    
    const GRState* St = GetState(Pred);
    
    for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
                                   OE = A->end_outputs(); OI != OE; ++OI) {
      
      SVal X = GetSVal(St, *OI);      
      assert (!isa<NonLoc>(X));  // Should be an Lval, or unknown, undef.
Zhongxing Xu's avatar
Zhongxing Xu committed
        St = BindLoc(St, cast<Loc>(X), UnknownVal());
    MakeNode(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::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);
  getTF().EvalReturn(Dst, *this, *Builder, S, Pred);
  // Handle the case where no nodes where generated.
  if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {

  Expr* R = S->getRetValue();
  
  if (!R) {
  NodeSet Tmp;
  Visit(R, Pred, Tmp);
  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;
    }
    
//===----------------------------------------------------------------------===//
// Transfer functions: Binary operators.
//===----------------------------------------------------------------------===//

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);
    }
    
  }
  
  // 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);
      
    }
  
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
                                       GRExprEngine::NodeTy* Pred,
                                       GRExprEngine::NodeSet& Dst) {

  NodeSet Tmp1;
  Expr* LHS = B->getLHS()->IgnoreParens();
  Expr* RHS = B->getRHS()->IgnoreParens();
  // FIXME: Add proper support for ObjCKVCRefExpr.
  if (isa<ObjCKVCRefExpr>(LHS)) {
    Visit(RHS, Pred, Dst);   
    return;
  }
  
  
  if (B->isAssignmentOp())
  for (NodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1 != E1; ++I1) {
    SVal LeftV = GetSVal((*I1)->getState(), LHS);
    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) {
      const GRState* St = GetState(*I2);
      BinaryOperator::Opcode Op = B->getOpcode();
      
          // FIXME: Handle structs.
          QualType T = RHS->getType();
          if (RightV.isUnknown() && (Loc::IsLocType(T) || 
                                  (T->isScalarType() && T->isIntegerType()))) {
            unsigned Count = Builder->getCurrentBlockCount();
            SymbolRef Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
                   ? cast<SVal>(loc::SymbolVal(Sym)) 
                   : cast<SVal>(nonloc::SymbolVal(Sym));            
          }
          
          // Simulate the effects of a "store":  bind the value of the RHS
          // to the L-Value represented by the LHS.
Zhongxing Xu's avatar
Zhongxing Xu committed
          EvalStore(Dst, B, LHS, *I2, BindExpr(St, B, RightV), LeftV, RightV);
        case BinaryOperator::Div:
        case BinaryOperator::Rem:
          // Special checking for integer denominators.          
          if (RHS->getType()->isIntegerType() && 
              RHS->getType()->isScalarType()) {
            
            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).
          
          SVal Result = EvalBinOp(Op, LeftV, RightV);
            if (OldSt != St) {
              // Generate a new node if we have already created a new state.
              MakeNode(Dst, B, *I2, St);
            }
            else
              Dst.Add(*I2);
            
          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);
            }
            
          // Otherwise, create a new node.
Zhongxing Xu's avatar
Zhongxing Xu committed
          MakeNode(Dst, B, *I2, BindExpr(St, B, Result));
      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;
      EvalLoad(Tmp3, LHS, *I2, St, location);
      
      for (NodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) {
        
        St = GetState(*I3);
        // Check for divide-by-zero.
        if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
            && RHS->getType()->isIntegerType()
            && RHS->getType()->isScalarType()) {
          
          // 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's avatar
Zhongxing Xu committed
          EvalStore(Dst, B, LHS, *I3, BindExpr(St, B, V), location, V);
          continue;
        }
        
        // Propagate unknown values (left and right-side).
        if (RightV.isUnknown() || V.isUnknown()) {
Zhongxing Xu's avatar
Zhongxing Xu committed
          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());
        if (LTy != CTy) V = EvalCast(V, CTy);
        if (RTy != CTy) RightV = EvalCast(RightV, CTy);
        // Evaluate operands and promote to result type.                    
Zhongxing Xu's avatar
Zhongxing Xu committed
          EvalStore(Dst,B, LHS, *I3, BindExpr(St, B, RightV), location, RightV);
        // Compute the result of the operation.      
        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);

        // 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.
          SymbolRef Sym = SymMgr.getConjuredSymbol(B->getRHS(), LTy, Count);
          LHSVal = Loc::IsLocType(LTy) 
                 : cast<SVal>(nonloc::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);
//===----------------------------------------------------------------------===//
// Transfer-function Helpers.
//===----------------------------------------------------------------------===//

void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
                             ExplodedNode<GRState>* Pred) {
  GRStateSet OStates;
  EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R);

  for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I)
void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* St,
  GRStateSet::AutoPopulate AP(OStates, St);
  if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, St, Ex, Op, L, R);
//===----------------------------------------------------------------------===//
// Visualization.
//===----------------------------------------------------------------------===//

static GRExprEngine* GraphPrintCheckerState;
static SourceManager* GraphPrintSourceManager;
struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
  static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) {
    
    if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
        GraphPrintCheckerState->isExplicitNullDeref(N) ||
        GraphPrintCheckerState->isUndefDeref(N) ||
        GraphPrintCheckerState->isUndefStore(N) ||
        GraphPrintCheckerState->isUndefControlFlow(N) ||
        GraphPrintCheckerState->isExplicitBadDivide(N) ||
        GraphPrintCheckerState->isImplicitBadDivide(N) ||
        GraphPrintCheckerState->isUndefResult(N) ||
        GraphPrintCheckerState->isBadCall(N) ||
        GraphPrintCheckerState->isUndefArg(N))
      return "color=\"red\",style=\"filled\"";
    
    if (GraphPrintCheckerState->isNoReturnCall(N))
      return "color=\"blue\",style=\"filled\"";
    
  static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) {
    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: {
Ted Kremenek's avatar
Ted Kremenek committed
        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's avatar
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);
          }
          if (isa<SwitchStmt>(T)) {
            Stmt* Label = E.getDst()->getLabel();
            
            if (Label) {                        
              if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
                Out << "\\lcase ";
Ted Kremenek's avatar
Ted Kremenek committed
                llvm::raw_os_ostream OutS(Out);
                C->getLHS()->printPretty(OutS);
                OutS.flush();
              
                if (Stmt* RHS = C->getRHS()) {
                  Out << " .. ";
Ted Kremenek's avatar
Ted Kremenek committed
                  RHS->printPretty(OutS);
                  OutS.flush();
                }
                
                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";
        }
        if (GraphPrintCheckerState->isUndefControlFlow(N)) {
          Out << "\\|Control-flow based on\\lUndefined value.\\l";
    Out << "\\|StateID: " << (void*) N->getState() << "\\|";
Ted Kremenek's avatar
Ted Kremenek committed
    GRStateRef state(N->getState(), GraphPrintCheckerState->getStateManager());
    state.printDOT(Out);

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;
}

static void AddSources(std::vector<GRExprEngine::NodeTy*>& Sources,
  llvm::SmallSet<ProgramPoint,10> CachedSources;
  for ( ; I != E; ++I ) {
    GRExprEngine::NodeTy* N = GetGraphNode(I);
    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();
Ted Kremenek's avatar
Ted Kremenek committed
    
  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;
  }