Skip to content
GRExprEngine.cpp 75.8 KiB
Newer Older
  }
  
  // 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();
  
  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() && (T->isIntegerType() || Loc::IsLocType(T))) {            
            unsigned Count = Builder->getCurrentBlockCount();
            SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
            
            RightV = Loc::IsLocType(B->getRHS()->getType()) 
                   ? 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.
          EvalStore(Dst, B, LHS, *I2, SetSVal(St, B, RightV), LeftV, RightV);
        case BinaryOperator::Div:
        case BinaryOperator::Rem:
          // 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).
          
          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.
          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;
      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()) {
          
          // 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()) {
          EvalStore(Dst, B, LHS, *I3, SetSVal(St, B, V), location, V);
          continue;
        }
        
        // Propagate unknown values (left and right-side).
        if (RightV.isUnknown() || V.isUnknown()) {
          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.                    
          EvalStore(Dst, B, LHS, *I3, SetSVal(St, B, RightV), location, RightV);
          continue;
        }
      
        // Compute the result of the operation.
      
        SVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType());
          // 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() &&
            (CTy->isIntegerType() || Loc::IsLocType(CTy))) {
          
          unsigned Count = Builder->getCurrentBlockCount();
          SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
          
                 ? cast<SVal>(loc::SymbolVal(Sym)) 
                 : cast<SVal>(nonloc::SymbolVal(Sym));            
        }
        EvalStore(Dst, B, LHS, *I3, SetSVal(St, B, Result), location, Result);
//===----------------------------------------------------------------------===//
// 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, StateMgr, 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;
        
      case ProgramPoint::PostLoadKind:
      case ProgramPoint::PostPurgeDeadSymbolsKind:
      case ProgramPoint::PostStmtKind: {
        const PostStmt& L = cast<PostStmt>(Loc);        
        Stmt* S = L.getStmt();
        SourceLocation SLoc = S->getLocStart();

        Out << S->getStmtClassName() << ' ' << (void*) S << ' ';        
Ted Kremenek's avatar
Ted Kremenek committed
        llvm::raw_os_ostream OutS(Out);
        S->printPretty(OutS);
        OutS.flush();
        if (SLoc.isFileID()) {        
          Out << "\\lline="
            << GraphPrintSourceManager->getLineNumber(SLoc) << " col="
Zhongxing Xu's avatar
Zhongxing Xu committed
            << 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))
        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;
      }
    
      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'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;
  }