Skip to content
GRExprEngine.cpp 81.2 KiB
Newer Older
const GRState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
Zhongxing Xu's avatar
Zhongxing Xu committed
                                          const GRState* St,
                                          SVal location, bool isLoad) {
  
  // Check for loads/stores from/to undefined values.  
  if (location.isUndef()) {
    ProgramPoint::Kind K =
      isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;
    
    if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, K)) {
      Succ->markAsSink();
      UndefDeref.insert(Succ);
    }
    
    return NULL;
  }
  
  // Check for loads/stores from/to unknown locations.  Treat as No-Ops.
  if (location.isUnknown())
    return St;
  
  // During a load, one of two possible situations arise:
  //  (1) A crash, because the location (pointer) was NULL.
  //  (2) The location (pointer) is not NULL, and the dereference works.
  // 
  // We add these assumptions.
  
  
  // "Assume" that the pointer is not NULL.
  
  bool isFeasibleNotNull = false;
  const GRState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
  
  // "Assume" that the pointer is NULL.
  
  bool isFeasibleNull = false;
  GRStateRef StNull = GRStateRef(Assume(St, LV, false, isFeasibleNull),
                                 getStateManager());
    // Use the Generic Data Map to mark in the state what lval was null.
    const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV);
    StNull = StNull.set<GRState::NullDerefTag>(PersistentLV);
    
    // We don't use "MakeNode" here because the node will be a sink
    // and we have no intention of processing it later.
    
    ProgramPoint::Kind K =
      isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;

    NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, K);
    
    if (NullNode) {
      
      NullNode->markAsSink();
      
      if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
      else ExplicitNullDeref.insert(NullNode);
    }
  }
  
  return isFeasibleNotNull ? StNotNull : NULL;
//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
                             CallExpr::arg_iterator AI,
                             CallExpr::arg_iterator AE,
                             NodeSet& Dst)
{
  // Determine the type of function we're calling (if available).
  const FunctionTypeProto *Proto = NULL;
  QualType FnType = CE->getCallee()->IgnoreParens()->getType();
  if (const PointerType *FnTypePtr = FnType->getAsPointerType())
    Proto = FnTypePtr->getPointeeType()->getAsFunctionTypeProto();

  VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
}

void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
                                CallExpr::arg_iterator AI,
                                CallExpr::arg_iterator AE,
                                NodeSet& Dst, const FunctionTypeProto *Proto,
                                unsigned ParamIdx) {
  // Process the arguments.
  if (AI != AE) {
    // If the call argument is being bound to a reference parameter,
    // visit it as an lvalue, not an rvalue.
    bool VisitAsLvalue = false;
    if (Proto && ParamIdx < Proto->getNumArgs())
      VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();

    NodeSet DstTmp;  
    if (VisitAsLvalue)
      VisitLValue(*AI, Pred, DstTmp);    
    else
      Visit(*AI, Pred, DstTmp);    
    for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
      VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1);
    
    return;
  }

  // If we reach here we have processed all of the arguments.  Evaluate
  // the callee expression.
Ted Kremenek's avatar
Ted Kremenek committed
  
  Expr* Callee = CE->getCallee()->IgnoreParens();
Ted Kremenek's avatar
Ted Kremenek committed

Ted Kremenek's avatar
Ted Kremenek committed
  
  // Finally, evaluate the function call.
  for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {

    const GRState* St = GetState(*DI);
Ted Kremenek's avatar
Ted Kremenek committed
    // FIXME: Add support for symbolic function calls (calls involving
    //  function pointer values that are symbolic).
    
    // Check for undefined control-flow or calls to NULL.
    
    if (L.isUndef() || isa<loc::ConcreteInt>(L)) {      
      NodeTy* N = Builder->generateNode(CE, St, *DI);
    }
    
    // Check for the "noreturn" attribute.
    
    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
    
      FunctionDecl* FD = cast<loc::FuncVal>(L).getDecl();
      else {
        // HACK: Some functions are not marked noreturn, and don't return.
        //  Here are a few hardwired ones.  If this takes too long, we can
        //  potentially cache these results.
        const char* s = FD->getIdentifier()->getName();
        unsigned n = strlen(s);
        
        switch (n) {
          default:
            break;
            if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true;
            break;

          case 5:
            if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true;
            else if (!memcmp(s, "error", 5)) {
                SVal X = GetSVal(St, *CE->arg_begin());
                // FIXME: use Assume to inspect the possible symbolic value of
                // X. Also check the specific signature of error().
                nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&X);
                if (CI && CI->getValue() != 0)
                  Builder->BuildSinks = true;
            if (!memcmp(s, "Assert", 6)) {
              Builder->BuildSinks = true;
              break;
            }
            
            // FIXME: This is just a wrapper around throwing an exception.
            //  Eventually inter-procedural analysis should handle this easily.
            if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true;

            break;
          
          case 7:
            if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true;
          case 8:
            if (!memcmp(s ,"db_error", 8)) Builder->BuildSinks = true;
            break;
          
          case 12:
            if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true;
            break;
          case 13:
            if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true;
            break;
            
            if (!memcmp(s, "dtrace_assfail", 14) ||
                !memcmp(s, "yy_fatal_error", 14))
              Builder->BuildSinks = true;
Ted Kremenek's avatar
Ted Kremenek committed
            if (!memcmp(s, "_XCAssertionFailureHandler", 26) ||
                !memcmp(s, "_DTAssertionFailureHandler", 26))
Ted Kremenek's avatar
Ted Kremenek committed
              Builder->BuildSinks = true;
Ted Kremenek's avatar
Ted Kremenek committed

      IdentifierInfo* Info = cast<loc::FuncVal>(L).getDecl()->getIdentifier();
      if (unsigned id = Info->getBuiltinID())
        switch (id) {
          case Builtin::BI__builtin_expect: {
            // For __builtin_expect, just return the value of the subexpression.
            assert (CE->arg_begin() != CE->arg_end());            
            SVal X = GetSVal(St, *(CE->arg_begin()));
Zhongxing Xu's avatar
Zhongxing Xu committed
            MakeNode(Dst, CE, *DI, BindExpr(St, CE, X));
    // Check any arguments passed-by-value against being undefined.
    bool badArg = false;
    
    for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
         I != E; ++I) {
      if (GetSVal(GetState(*DI), *I).isUndef()) {        
        NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI);
      
        if (N) {
          N->markAsSink();
          UndefArgs[N] = *I;
        badArg = true;
        break;
      }
    
    if (badArg)
      continue;        

    // Dispatch to the plug-in transfer function.      
    
    unsigned size = Dst.size();
    SaveOr OldHasGen(Builder->HasGeneratedNode);
    EvalCall(Dst, CE, L, *DI);
    
    // 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)
      MakeNode(Dst, CE, *DI, St);
//===----------------------------------------------------------------------===//
// Transfer function: Objective-C ivar references.
//===----------------------------------------------------------------------===//

void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
                                            NodeTy* Pred, NodeSet& Dst,
                                            bool asLValue) {
  
  Expr* Base = cast<Expr>(Ex->getBase());
  NodeSet Tmp;
  Visit(Base, Pred, Tmp);
  
  for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
    const GRState* St = GetState(*I);
    SVal BaseVal = GetSVal(St, Base);
    SVal location = StateMgr.GetLValue(St, Ex->getDecl(), BaseVal);
Zhongxing Xu's avatar
Zhongxing Xu committed
      MakeNode(Dst, Ex, *I, BindExpr(St, Ex, location));
    else
      EvalLoad(Dst, Ex, *I, St, location);
  }
}

//===----------------------------------------------------------------------===//
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//

void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred,
                                        NodeSet& Dst){
  
  VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
                                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. 
  
  const GRState* St = GetState(Pred);
    
    // 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 if the "raise" message was sent.
    if (ME->getSelector() == RaiseSel)
      RaisesException = true;
  }
  else {
    
    IdentifierInfo* ClsName = ME->getClassName();
    Selector S = ME->getSelector();
    
    // Check for special instance methods.
        
    if (!NSExceptionII) {      
      ASTContext& Ctx = getContext();
      
      NSExceptionII = &Ctx.Idents.get("NSException");
    }
    
    if (ClsName == NSExceptionII) {
        
      enum { NUM_RAISE_SELECTORS = 2 };
      
      // Lazily create a cache of the selectors.

      if (!NSExceptionInstanceRaiseSelectors) {
        
        ASTContext& Ctx = getContext();
        
        NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
      
        llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
        unsigned idx = 0;
        
        // raise:format:      
        II.push_back(&Ctx.Idents.get("raise"));
        II.push_back(&Ctx.Idents.get("format"));      
        NSExceptionInstanceRaiseSelectors[idx++] =
          Ctx.Selectors.getSelector(II.size(), &II[0]);      
        
        // raise:format::arguments:      
        II.push_back(&Ctx.Idents.get("arguments"));
        NSExceptionInstanceRaiseSelectors[idx++] =
          Ctx.Selectors.getSelector(II.size(), &II[0]);
      }
      
      for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
        if (S == NSExceptionInstanceRaiseSelectors[i]) {
          RaisesException = true; break;
        }
    }
  }
  
  // Check for any arguments that are uninitialized/undefined.
  
  for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
       I != E; ++I) {
    
      
      // 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;
    }    
  }
  
  // Check if we raise an exception.  For now treat these as sinks.  Eventually
  // we will want to handle exceptions properly.
  
  SaveAndRestore<bool> OldSink(Builder->BuildSinks);

  if (RaisesException)
    Builder->BuildSinks = true;
  
  // Dispatch to plug-in transfer function.
  
  unsigned size = Dst.size();
  SaveOr 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){
  NodeSet S1;
  QualType T = CastE->getType();
  QualType ExTy = Ex->getType();
  if (const ExplicitCastExpr *ExCast = dyn_cast_or_null<ExplicitCastExpr>(CastE))
    T = ExCast->getTypeAsWritten();

  if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType())
  // 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.
  
  for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
    const GRState* St = GetState(N);
Zhongxing Xu's avatar
Zhongxing Xu committed
      MakeNode(Dst, CastE, N, BindExpr(St, CastE, V));
    
    // For const casts, just propagate the value.
    ASTContext& C = getContext();
    
    if (C.getCanonicalType(T).getUnqualifiedType() == 
        C.getCanonicalType(ExTy).getUnqualifiedType()) {
Zhongxing Xu's avatar
Zhongxing Xu committed
      MakeNode(Dst, CastE, N, BindExpr(St, CastE, V));
    if (T->isIntegerType() && Loc::IsLocType(ExTy)) {
      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 = nonloc::LocAsInteger::Make(getBasicVals(), cast<Loc>(V), bits);
Zhongxing Xu's avatar
Zhongxing Xu committed
      MakeNode(Dst, CastE, N, BindExpr(St, CastE, V));
      continue;
    }
    
    // Check for casts from integers to pointers.
    if (Loc::IsLocType(T) && ExTy->isIntegerType())
      if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&V)) {
        // Just unpackage the lval and return it.
Zhongxing Xu's avatar
Zhongxing Xu committed
        MakeNode(Dst, CastE, N, BindExpr(St, CastE, V));

    // StoreManager casts array to different values.
    if (ExTy->isArrayType()) {
      assert(T->isPointerType() || T->isReferenceType());
Zhongxing Xu's avatar
Zhongxing Xu committed
      MakeNode(Dst, CastE, N, BindExpr(St, CastE, V));
Zhongxing Xu's avatar
Zhongxing Xu committed
    MakeNode(Dst, CastE, N, BindExpr(St, CastE, EvalCast(V, CastE->getType())));
void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL,
                                            NodeTy* Pred, NodeSet& Dst) {

  // FIXME: Can getInitializer() be NULL?
  InitListExpr* ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
  NodeSet Tmp;
  Visit(ILE, Pred, Tmp);
  
  for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
    // Retrieve the initializer values from the environment and store them
    // into a vector that will then be handed off to the Store.    
    const GRState* St = GetState(*I);    
    llvm::SmallVector<SVal, 10> IVals;
    IVals.reserve(ILE->getNumInits());
    
    for (Stmt::child_iterator J=ILE->child_begin(), EJ=ILE->child_end();
          J!=EJ; ++J)
      IVals.push_back(GetSVal(St, cast<Expr>(*J)));

    const CompoundLiteralRegion* R = 
      StateMgr.getRegionManager().getCompoundLiteralRegion(CL);
    
    assert (!IVals.empty() && "Initializer cannot be empty.");

    St = StateMgr.BindCompoundLiteral(St, R, &IVals[0], &IVals[0]+IVals.size());
Zhongxing Xu's avatar
Zhongxing Xu committed
    MakeNode(Dst, CL, *I, BindExpr(St, CL, loc::MemRegionVal(R)));
void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {  

  // The CFG has one DeclStmt per Decl.  
  ScopedDecl* D = *DS->decl_begin();
  if (!D || !isa<VarDecl>(D))
    return;
  
  const VarDecl* VD = dyn_cast<VarDecl>(D);
  
  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) {
    const GRState* St = GetState(*I);
    St = StateMgr.BindDecl(St, VD, Ex, Builder->getCurrentBlockCount());
    MakeNode(Dst, DS, *I, St);
namespace {
  // This class is used by VisitInitListExpr as an item in a worklist
  // for processing the values contained in an InitListExpr.
class VISIBILITY_HIDDEN InitListWLItem {
public:
  llvm::ImmutableList<SVal> Vals;
  GRExprEngine::NodeTy* N;
  InitListExpr::reverse_iterator Itr;
  
  InitListWLItem(GRExprEngine::NodeTy* n, llvm::ImmutableList<SVal> vals,
         InitListExpr::reverse_iterator itr)
  : Vals(vals), N(n), Itr(itr) {}
};
}


void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred, 
                                     NodeSet& Dst) {
  const GRState* state = GetState(Pred);

  QualType T = E->getType();

  unsigned NumInitElements = E->getNumInits();  
  if (T->isArrayType() || T->isStructureType()) {
    llvm::SmallVector<InitListWLItem, 10> WorkList;
    WorkList.reserve(NumInitElements);
  
    WorkList.push_back(InitListWLItem(Pred, getBasicVals().getEmptySValList(),
                              E->rbegin()));
    
    InitListExpr::reverse_iterator ItrEnd = E->rend();
    
    while (!WorkList.empty()) {
      InitListWLItem X = WorkList.back();
      WorkList.pop_back();
      
      NodeSet Tmp;
      Visit(*X.Itr, X.N, Tmp);
      
      InitListExpr::reverse_iterator NewItr = X.Itr + 1;
      for (NodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
        // Get the last initializer value.
        state = GetState(*NI);
        SVal InitV = GetSVal(state, cast<Expr>(*X.Itr));
        
        // Construct the new list of values by prepending the new value to
        // the already constructed list.
        llvm::ImmutableList<SVal> NewVals =
          getBasicVals().consVals(InitV, X.Vals);
        
        if (NewItr == ItrEnd) {
          // Now we have a list holding all init values. Make CompoundSValData.
          SVal V = NonLoc::MakeCompoundVal(T, NewVals, getBasicVals());
          // Make final state and node.
          MakeNode(Dst, E, Pred,  BindExpr(state, E, V));
        }
        else {
          // Still some initializer values to go.  Push them onto the worklist.
          WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
        }
      }
    }
  }

  if (Loc::IsLocType(T) || T->isIntegerType()) {
    assert (E->getNumInits() == 1);
    NodeSet Tmp;
    Expr* Init = E->getInit(0);
    Visit(Init, Pred, Tmp);
    for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) {
      state = GetState(*I);
Zhongxing Xu's avatar
Zhongxing Xu committed
      MakeNode(Dst, E, *I, BindExpr(state, E, GetSVal(state, Init)));
    }
    return;
  }

  if (T->isUnionType()) {
    // FIXME: to be implemented.
    MakeNode(Dst, E, Pred, state);
    return;
  }

  printf("InitListExpr type = %s\n", T.getAsString().c_str());
  assert(0 && "unprocessed InitListExpr type");
}
/// 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;
    
    // Some code tries to take the sizeof an ObjCInterfaceType, relying that
    // the compiler has laid out its representation.  Just report Unknown
    // for these.
    if (T->isObjCInterfaceType())
      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,
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);
        // FIXME: This is the right thing to do, but it currently breaks
        //  a bunch of tests.
        // V = EvalCast(V, U->getType()); 
Zhongxing Xu's avatar
Zhongxing Xu committed
          MakeNode(Dst, U, *I, BindExpr(St, U, V));
        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);
     
    case UnaryOperator::AlignOf: {
      
      QualType T = U->getSubExpr()->getType();
      
      // FIXME: Add support for VLAs.
      
      if (!T.getTypePtr()->isConstantSizeType())
        return;
      
      uint64_t size = getContext().getTypeAlign(T) / 8;                
      const GRState* St = GetState(Pred);
Zhongxing Xu's avatar
Zhongxing Xu committed
      St = BindExpr(St, U, NonLoc::MakeVal(getBasicVals(), size, U->getType()));
      
    case UnaryOperator::SizeOf: {
            
      QualType T = U->getSubExpr()->getType();
      // FIXME: Add support for VLAs.
      
      if (!T.getTypePtr()->isConstantSizeType())
        return;
      uint64_t size = getContext().getTypeSize(T) / 8;                
      const GRState* St = GetState(Pred);
Zhongxing Xu's avatar
Zhongxing Xu committed
      St = BindExpr(St, U, NonLoc::MakeVal(getBasicVals(), size, U->getType()));
  // 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));