Skip to content
GRExprEngine.cpp 73.6 KiB
Newer Older
                                Pred, Dst);
}  

void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
                                                 ObjCMessageExpr::arg_iterator AI,
                                                 ObjCMessageExpr::arg_iterator AE,
                                                 NodeTy* Pred, NodeSet& Dst) {
  if (AI == AE) {
    
    // Process the receiver.
    
    if (Expr* Receiver = ME->getReceiver()) {
      NodeSet Tmp;
      Visit(Receiver, Pred, Tmp);
      
      for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
        VisitObjCMessageExprDispatchHelper(ME, *NI, Dst);
      
      return;
    }
    
    VisitObjCMessageExprDispatchHelper(ME, Pred, Dst);
    return;
  }
  
  NodeSet Tmp;
  Visit(*AI, Pred, Tmp);
  
  ++AI;
  
  for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
    VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst);
}

void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
                                                      NodeTy* Pred,
                                                      NodeSet& Dst) {
  
  // FIXME: More logic for the processing the method call. 
  
  ValueState* St = GetState(Pred);
  
  if (Expr* Receiver = ME->getReceiver()) {
    
    RVal L = GetRVal(St, Receiver);
    
    // Check for undefined control-flow or calls to NULL.
    
    if (L.isUndef()) {
      NodeTy* N = Builder->generateNode(ME, St, Pred);
      
      if (N) {
        N->markAsSink();
        UndefReceivers.insert(N);
      }
      
      return;
    }
  }
  
  // Check for any arguments that are uninitialized/undefined.
  
  for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
       I != E; ++I) {
    
    if (GetRVal(St, *I).isUndef()) {
      
      // Generate an error node for passing an uninitialized/undefined value
      // as an argument to a message expression.  This node is a sink.
      NodeTy* N = Builder->generateNode(ME, St, Pred);
      
      if (N) {
        N->markAsSink();
        MsgExprUndefArgs[N] = *I;
      }
      
      return;
    }    
  }    
  // Dispatch to plug-in transfer function.
  
  unsigned size = Dst.size();

  SaveAndRestore<bool> OldSink(Builder->BuildSinks),
                       OldHasGen(Builder->HasGeneratedNode);
  EvalObjCMessageExpr(Dst, ME, Pred);
  
  // Handle the case where no nodes where generated.  Auto-generate that
  // contains the updated state if we aren't generating sinks.
  
  if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
//===----------------------------------------------------------------------===//
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//

void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
  if (T->isReferenceType())
    VisitLVal(Ex, Pred, S1);
  else
    Visit(Ex, Pred, S1);
  
  // Check for casting to "void".
  if (T->isVoidType()) {
    for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1)
  // FIXME: The rest of this should probably just go into EvalCall, and
  //   let the transfer function object be responsible for constructing
  //   nodes.
  
  QualType ExTy = Ex->getType();
  
  for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
    RVal V = T->isReferenceType() ? GetLVal(St, Ex) : GetRVal(St, Ex);

    // Unknown?
    
    if (V.isUnknown()) {
      Dst.Add(N);
      continue;
    }
    
    // Undefined?
    
    if (V.isUndef()) {
      MakeNode(Dst, CastE, N, SetRVal(St, CastE, V));
      continue;
    }
  
    // Check for casts from pointers to integers.
    if (T->isIntegerType() && ExTy->isPointerType()) {
      unsigned bits = getContext().getTypeSize(ExTy);
    
      // FIXME: Determine if the number of bits of the target type is 
      // equal or exceeds the number of bits to store the pointer value.
      // If not, flag an error.
      
      V = nonlval::LValAsInteger::Make(BasicVals, cast<LVal>(V), bits);
      MakeNode(Dst, CastE, N, SetRVal(St, CastE, V));
      continue;
    }
    
    // Check for casts from integers to pointers.
    if (T->isPointerType() && ExTy->isIntegerType())
      if (nonlval::LValAsInteger *LV = dyn_cast<nonlval::LValAsInteger>(&V)) {
        // Just unpackage the lval and return it.
        V = LV->getLVal();
        MakeNode(Dst, CastE, N, SetRVal(St, CastE, V));
        continue;
      }
    
    // All other cases.
    MakeNode(Dst, CastE, N, SetRVal(St, CastE, EvalCast(V, CastE->getType())));
void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {  
  VisitDeclStmtAux(DS, DS->getDecl(), Pred, Dst);
}

void GRExprEngine::VisitDeclStmtAux(DeclStmt* DS, ScopedDecl* D,
                                    NodeTy* Pred, NodeSet& Dst) {

  if (!D)
    return;
  if (!isa<VarDecl>(D)) {
    VisitDeclStmtAux(DS, D->getNextDeclarator(), Pred, Dst);
    return;
  }
  
  const VarDecl* VD = dyn_cast<VarDecl>(D);
  
  // FIXME: Add support for local arrays.
  if (VD->getType()->isArrayType()) {
    VisitDeclStmtAux(DS, D->getNextDeclarator(), Pred, Dst);
    return;
  }
  Expr* Ex = const_cast<Expr*>(VD->getInit());

  // FIXME: static variables may have an initializer, but the second
  //  time a function is called those values may not be current.
  NodeSet Tmp;

  if (Ex) Visit(Ex, Pred, Tmp);
  if (Tmp.empty()) Tmp.Add(Pred);
  
  for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
    ValueState* St = GetState(*I);

    if (!Ex && VD->hasGlobalStorage()) {
      // Handle variables with global storage and no initializers.
      // FIXME: static variables may have an initializer, but the second
      //  time a function is called those values may not be current.
      
      
      // In this context, Static => Local variable.
      
      assert (!VD->getStorageClass() == VarDecl::Static ||
              !VD->isFileVarDecl());
      
      // If there is no initializer, set the value of the
      // variable to "Undefined".
      
      if (VD->getStorageClass() == VarDecl::Static) {
          
        // C99: 6.7.8 Initialization
        //  If an object that has static storage duration is not initialized
        //  explicitly, then: 
        //   —if it has pointer type, it is initialized to a null pointer; 
        //   —if it has arithmetic type, it is initialized to (positive or 
        //     unsigned) zero; 
        // FIXME: Handle structs.  Now we treat their values as unknown.
        if (T->isPointerType())          
          St = SetRVal(St, lval::DeclVal(VD),
                       lval::ConcreteInt(BasicVals.getValue(0, T)));
        else if (T->isIntegerType())
          St = SetRVal(St, lval::DeclVal(VD),
                       nonlval::ConcreteInt(BasicVals.getValue(0, T)));          
        // FIXME: Handle structs.  Now we treat them as unknown.  What
        //  we need to do is treat their members as unknown.
    else {
      
      // FIXME: Handle structs.  Now we treat them as unknown.  What
      //  we need to do is treat their members as unknown.
      if (T->isPointerType() || T->isIntegerType())
        St = SetRVal(St, lval::DeclVal(VD),
                     Ex ? GetRVal(St, Ex) : UndefinedVal());
    }

    // Create a new node.  We don't really need to create a new NodeSet
    // here, but it simplifies things and doesn't cost much.
    NodeSet Tmp2;    
    MakeNode(Tmp2, DS, *I, St);
    if (Tmp2.empty()) Tmp2.Add(*I);
    
    for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2)
      VisitDeclStmtAux(DS, D->getNextDeclarator(), *I2, Dst);
  }
}
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex,
                                              NodeTy* Pred,
                                              NodeSet& Dst) {
  QualType T = Ex->getArgumentType();
  if (Ex->isSizeOf()) {

    // FIXME: Add support for VLAs.
    if (!T.getTypePtr()->isConstantSizeType())
      return;
    
    amt = 1;  // Handle sizeof(void)
    
    if (T != getContext().VoidTy)
      amt = getContext().getTypeSize(T) / 8;
    
  }
  else  // Get alignment of the type.
    amt = getContext().getTypeAlign(T) / 8;
  MakeNode(Dst, Ex, Pred,
                 NonLVal::MakeVal(BasicVals, amt, Ex->getType())));  
void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred,
                              NodeSet& Dst, bool GetLVal) {
  Expr* Ex = U->getSubExpr()->IgnoreParens();
Ted Kremenek's avatar
Ted Kremenek committed
  if (isa<DeclRefExpr>(Ex))
  for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) {
    VisitDeref(U, V, St, Pred, Dst, GetLVal);
  }
}

void GRExprEngine::VisitDeref(Expr* Ex, RVal V, ValueState* St, NodeTy* Pred,
                              NodeSet& Dst, bool GetLVal) {
  
  // Check for dereferences of undefined values.
  
  if (V.isUndef()) {
    if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred)) {
      Succ->markAsSink();
      UndefDeref.insert(Succ);
    return;
  }
  
  // Check for dereferences of unknown values.  Treat as No-Ops.
  
  if (V.isUnknown()) {
    Dst.Add(Pred);
    return;
  }
  
  // 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.
  
  LVal LV = cast<LVal>(V);    
  bool isFeasibleNotNull;
  
  // "Assume" that the pointer is Not-NULL.
  
  ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
  
  if (isFeasibleNotNull) {
    if (GetLVal)
      MakeNode(Dst, Ex, Pred, SetRVal(StNotNull, Ex, LV));
    else {
      // FIXME: Currently symbolic analysis "generates" new symbols
      //  for the contents of values.  We need a better approach.
      
      MakeNode(Dst, Ex, Pred,
               SetRVal(StNotNull, Ex, GetRVal(StNotNull, LV, Ex->getType())));
  }
  
  bool isFeasibleNull;
  
  // Now "assume" that the pointer is NULL.
  
  ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
  
  if (isFeasibleNull) {
    // We don't use "MakeNode" here because the node will be a sink
    // and we have no intention of processing it later.
    NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred);
      if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
      else ExplicitNullDeref.insert(NullNode);
    }
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
                                      NodeSet& Dst) {
  
  NodeSet S1;
  
  assert (U->getOpcode() != UnaryOperator::Deref);
  assert (U->getOpcode() != UnaryOperator::SizeOf);
  assert (U->getOpcode() != UnaryOperator::AlignOf);
  
  bool use_GetLVal = false;
  
  switch (U->getOpcode()) {
    case UnaryOperator::PostInc:
    case UnaryOperator::PostDec:
    case UnaryOperator::PreInc:
    case UnaryOperator::PreDec:
    case UnaryOperator::AddrOf:
      // Evalue subexpression as an LVal.
      use_GetLVal = true;
      VisitLVal(U->getSubExpr(), Pred, S1);
  for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
        
    RVal SubV = use_GetLVal ? GetLVal(St, U->getSubExpr()) : 
                              GetRVal(St, U->getSubExpr());
    
    if (SubV.isUnknown()) {
      Dst.Add(N1);
      continue;
    }

      MakeNode(Dst, U, N1, SetRVal(St, U, SubV));
    if (U->isIncrementDecrementOp()) {
      
      // Handle ++ and -- (both pre- and post-increment).
      
      LVal SubLV = cast<LVal>(SubV); 
      RVal V  = GetRVal(St, SubLV, U->getType());
      
      // Propagate undefined values.      
      if (V.isUndef()) {
        MakeNode(Dst, U, N1, SetRVal(St, U, V));
      // Handle all other values.
      
      BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
                                                     : BinaryOperator::Sub;
      
      RVal Result = EvalBinOp(Op, V, MakeConstantVal(1U, U));
        St = SetRVal(SetRVal(St, U, V), SubLV, Result);
        St = SetRVal(SetRVal(St, U, Result), SubLV, Result);
      MakeNode(Dst, U, N1, St);
      continue;
    }    
    
    // Handle all other unary operators.
    
    switch (U->getOpcode()) {
        
      case UnaryOperator::Extension:
        St = SetRVal(St, U, SubV);
        break;
      case UnaryOperator::Minus:
        St = SetRVal(St, U, EvalMinus(U, cast<NonLVal>(SubV)));
      case UnaryOperator::Not:
        St = SetRVal(St, U, EvalComplement(cast<NonLVal>(SubV)));
        // 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".
          lval::ConcreteInt V(BasicVals.getZeroWithPtrWidth());
          RVal Result = EvalBinOp(BinaryOperator::EQ, cast<LVal>(SubV), V);
          St = SetRVal(St, U, Result);
          nonlval::ConcreteInt V(BasicVals.getValue(0, Ex->getType()));
          RVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLVal>(SubV), V);
          St = SetRVal(St, U, Result);
        assert (isa<LVal>(SubV));
        St = SetRVal(St, U, SubV);
      default: ;
        assert (false && "Not implemented.");
    MakeNode(Dst, U, N1, St);
void GRExprEngine::VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred,
                                   NodeSet& Dst) {
  QualType T = U->getSubExpr()->getType();
  
  // FIXME: Add support for VLAs.
  if (!T.getTypePtr()->isConstantSizeType())
    return;
  uint64_t size = getContext().getTypeSize(T) / 8;                
  St = SetRVal(St, U, NonLVal::MakeVal(BasicVals, size, U->getType()));
  MakeNode(Dst, U, Pred, St);
}

void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
    case Stmt::ArraySubscriptExprClass:
      VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
      return;

      
    case Stmt::UnaryOperatorClass: {
      UnaryOperator* U = cast<UnaryOperator>(Ex);
      
      if (U->getOpcode() == UnaryOperator::Deref) {
        VisitDeref(U, Pred, Dst, true);
        return;
      }
      
      break;
      
    case Stmt::MemberExprClass:
      VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
      return;
  }
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;
  VisitLVal(*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
    // should evaluate to LVals.  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.
    
    ValueState* St = GetState(Pred);
    
    for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
                                   OE = A->end_outputs(); OI != OE; ++OI) {
      
      RVal X = GetLVal(St, *OI);
      
      assert (!isa<NonLVal>(X));
      
      if (isa<LVal>(X))
        St = SetRVal(St, cast<LVal>(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),
                       OldHasGen(Builder->HasGeneratedNode);
  TF->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) {
  if (T->isPointerLikeType()) {
    
    // Check if any of the return values return the address of a stack variable.
    
    NodeSet Tmp;
    Visit(R, Pred, Tmp);
    
    for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
      RVal X = GetRVal((*I)->getState(), R);

      if (isa<lval::DeclVal>(X)) {
        
        if (cast<lval::DeclVal>(X).getDecl()->hasLocalStorage()) {
        
          // Create a special node representing the v
          
          NodeTy* RetStackNode = Builder->generateNode(S, GetState(*I), *I);
          
          if (RetStackNode) {
            RetStackNode->markAsSink();
            RetsStackAddr.insert(RetStackNode);
          }
          
          continue;
        }
      }
      
    Visit(R, Pred, DstRet);
  
  for (NodeSet::iterator I=DstRet.begin(), E=DstRet.end(); I!=E; ++I)
    EvalReturn(Dst, S, *I);
//===----------------------------------------------------------------------===//
// Transfer functions: Binary operators.
//===----------------------------------------------------------------------===//

void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
                                       GRExprEngine::NodeTy* Pred,
                                       GRExprEngine::NodeSet& Dst) {
  
  if (B->isAssignmentOp())
  else
    Visit(B->getLHS(), Pred, S1);
  for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++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 LVal,
    // so we use GetLVal instead of GetRVal so that DeclRefExpr's are
    // evaluated to LValDecl's instead of to an NonLVal.

    RVal LeftV = B->isAssignmentOp() ? GetLVal(GetState(N1), B->getLHS())
                                     : GetRVal(GetState(N1), B->getLHS());
    for (NodeSet::iterator I2 = S2.begin(), E2 = S2.end(); I2 != E2; ++I2) {
      Expr* RHS = B->getRHS();
      RVal RightV = GetRVal(St, RHS);
      BinaryOperator::Opcode Op = B->getOpcode();
      
      if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
          && RHS->getType()->isIntegerType()) {
        // Check if the denominator is undefined.
          if (RightV.isUndef()) {
            NodeTy* DivUndef = Builder->generateNode(B, St, N2);
              ExplicitBadDivides.insert(DivUndef);
          // First, "assume" that the denominator is 0 or undefined.
          bool isFeasibleZero = false;
          ValueState* ZeroSt =  Assume(St, RightV, false, isFeasibleZero);
          // Second, "assume" that the denominator cannot be 0.
          
          bool isFeasibleNotZero = false;
          St = Assume(St, RightV, true, isFeasibleNotZero);
          
          // Create the node for the divide-by-zero (if it occurred).
          
          if (isFeasibleZero)
            if (NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2)) {
              
              if (isFeasibleNotZero)
                ImplicitBadDivides.insert(DivZeroNode);
              else
                ExplicitBadDivides.insert(DivZeroNode);

        }
        
        // Fall-through.  The logic below processes the divide.
      }
      
        // Process non-assignements except commas or short-circuited
        // logical expressions (LAnd and LOr).
        
        RVal Result = EvalBinOp(Op, LeftV, RightV);
        
        if (Result.isUnknown()) {
          Dst.Add(N2);
        if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
          
          // The operands were not undefined, but the result is undefined.
          
          if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) {
            UndefNode->markAsSink();            
            UndefResults.insert(UndefNode);
          }
          
          continue;
        }
        
        MakeNode(Dst, B, N2, SetRVal(St, B, Result));
          if (LeftV.isUndef()) {
            HandleUndefinedStore(B, N2);
          // EXPERIMENTAL: "Conjured" symbols.
          
          if (RightV.isUnknown()) {            
            unsigned Count = Builder->getCurrentBlockCount();
            SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
            
            RightV = B->getRHS()->getType()->isPointerType() 
                     ? cast<RVal>(lval::SymbolVal(Sym)) 
                     : cast<RVal>(nonlval::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, N2, SetRVal(St, B, RightV),
          assert (B->isCompoundAssignmentOp());
          
          if (Op >= BinaryOperator::AndAssign)
            ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And);
          else
            ((int&) Op) -= BinaryOperator::MulAssign;  
          
          if (LeftV.isUndef()) {
            HandleUndefinedStore(B, N2);
            assert (isa<UnknownVal>(GetRVal(St, B)));
            Dst.Add(N2);
            continue;
          // At this pointer we know that the LHS evaluates to an LVal
          // that is neither "Unknown" or "Undefined."
          
          LVal LeftLV = cast<LVal>(LeftV);
          
          // Fetch the value of the LHS (the value of the variable, etc.).
          
          RVal V = GetRVal(GetState(N1), LeftLV, B->getLHS()->getType());
          // Propagate undefined value (left-side).  We
          // propogate undefined values for the RHS below when
          // we also check for divide-by-zero.
            St = SetRVal(St, B, V);
            break;
          }
          
          // Propagate unknown values.
          
            // The value bound to LeftV is unknown.  Thus we just
            // propagate the current node (as "B" is already bound to nothing).
            assert (isa<UnknownVal>(GetRVal(St, B)));
            assert (isa<UnknownVal>(GetRVal(St, B)));
            St = SetRVal(St, LeftLV, UnknownVal());
          // 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.
          if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
              && RHS->getType()->isIntegerType()) {
            
            // Check if the denominator is undefined.
            if (RightV.isUndef()) {
              NodeTy* DivUndef = Builder->generateNode(B, St, N2);
                ExplicitBadDivides.insert(DivUndef);
            // First, "assume" that the denominator is 0.
            
            bool isFeasibleZero = false;
            ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero);
            // Second, "assume" that the denominator cannot be 0.
            
            bool isFeasibleNotZero = false;
            St = Assume(St, RightV, true, isFeasibleNotZero);
            
            // Create the node for the divide-by-zero error (if it occurred).
            
            if (isFeasibleZero) {
              NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2);
              
              if (DivZeroNode) {
                DivZeroNode->markAsSink();
                
                if (isFeasibleNotZero)
                  ImplicitBadDivides.insert(DivZeroNode);
                else
                  ExplicitBadDivides.insert(DivZeroNode);
              continue;
            
            // Fall-through.  The logic below processes the divide.
          }
            // Propagate undefined values (right-side).
              St = SetRVal(SetRVal(St, B, RightV), LeftLV, RightV);
              break;
            }
            
          }
          RVal 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, N2)) {
              UndefNode->markAsSink();            
              UndefResults.insert(UndefNode);
            }
            
            continue;