Fix PR 4594 by refactoring almost all casting logic from GRExprEngine::VisitCast
to SValuator::EvalCast. In the process, the StoreManagers now use this new cast
machinery, and the hack in GRExprEngine::EvalBind to handle implicit casts
involving OSAtomicCompareAndSwap and friends has been removed (and replaced with
logic closer to the logic specific to those functions).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76641 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 7aa63c1..f276975 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -49,7 +49,8 @@
return new BasicStoreSubRegionMap();
}
- SVal Retrieve(const GRState *state, Loc loc, QualType T = QualType());
+ SValuator::CastResult Retrieve(const GRState *state, Loc loc,
+ QualType T = QualType());
const GRState *Bind(const GRState *state, Loc L, SVal V) {
return state->makeWithStore(BindInternal(state->getStore(), L, V));
@@ -269,10 +270,11 @@
}
}
-SVal BasicStoreManager::Retrieve(const GRState *state, Loc loc, QualType T) {
+SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
+ Loc loc, QualType T) {
if (isa<UnknownVal>(loc))
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
assert (!isa<UndefinedVal>(loc));
@@ -288,7 +290,7 @@
QualType T = ER->getLocationType(Ctx);
if (!isHigherOrderRawPtr(T, Ctx))
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
// FIXME: Should check for element 0.
// Otherwise, strip the element region.
@@ -296,25 +298,25 @@
}
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
BindingsTy B = GetBindings(state->getStore());
BindingsTy::data_type* T = B.lookup(R);
- return T ? *T : UnknownVal();
+ return SValuator::CastResult(state, T ? *T : UnknownVal());
}
case loc::ConcreteIntKind:
// Some clients may call GetSVal with such an option simply because
// they are doing a quick scan through their Locs (potentially to
// invalidate their bindings). Just return Undefined.
- return UndefinedVal();
+ return SValuator::CastResult(state, UndefinedVal());
default:
assert (false && "Invalid Loc.");
break;
}
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
}
Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
@@ -426,8 +428,8 @@
if (Marked.count(MR))
break;
- Marked.insert(MR);
- SVal X = Retrieve(state, loc::MemRegionVal(MR));
+ Marked.insert(MR);
+ SVal X = Retrieve(state, loc::MemRegionVal(MR)).getSVal();
// FIXME: We need to handle symbols nested in region definitions.
for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 6c49e8f..05bbd80 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -27,6 +27,7 @@
RangeConstraintManager.cpp
RegionStore.cpp
SVals.cpp
+ SValuator.cpp
SimpleConstraintManager.cpp
SimpleSValuator.cpp
Store.cpp
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 006c3a7..01cc033 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -1036,7 +1036,7 @@
/// EvalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by EvalStore and (soon) VisitDeclStmt, and others.
void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
- const GRState* state, SVal location, SVal Val) {
+ const GRState* state, SVal location, SVal Val) {
const GRState* newState = 0;
@@ -1049,24 +1049,7 @@
else {
// We are binding to a value other than 'unknown'. Perform the binding
// using the StoreManager.
- Loc L = cast<Loc>(location);
-
- // Handle implicit casts not reflected in the AST. This can be due to
- // custom checker logic such as what handles OSAtomicCompareAndSwap.
- if (!Val.isUnknownOrUndef())
- if (const TypedRegion *R =
- dyn_cast_or_null<TypedRegion>(L.getAsRegion())) {
- assert(R->isBoundable());
- QualType ValTy = R->getValueType(getContext());
- if (Loc::IsLocType(ValTy)) {
- if (!isa<Loc>(Val))
- Val = SVator.EvalCastNL(cast<NonLoc>(Val), ValTy);
- }
- else if (!isa<NonLoc>(Val))
- Val = SVator.EvalCastL(cast<Loc>(Val), ValTy);
- }
-
- newState = state->bindLoc(L, Val);
+ newState = state->bindLoc(cast<Loc>(location), Val);
}
// The next thing to do is check if the GRTransferFuncs object wants to
@@ -1343,8 +1326,18 @@
if (stateEqual) {
// Perform the store.
ExplodedNodeSet<GRState> TmpStore;
+ SVal val = stateEqual->getSVal(newValueExpr);
+
+ // Handle implicit value casts.
+ if (const TypedRegion *R =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ llvm::tie(state, val) =
+ Engine.getSValuator().EvalCast(val, state, R->getValueType(C),
+ newValueExpr->getType());
+ }
+
Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location,
- stateEqual->getSVal(newValueExpr), OSAtomicStoreTag);
+ val, OSAtomicStoreTag);
// Now bind the result of the comparison.
for (ExplodedNodeSet<GRState>::iterator I2 = TmpStore.begin(),
@@ -2034,22 +2027,6 @@
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCastPointerToInteger(SVal V, const GRState* state,
- QualType PtrTy,
- Expr* CastE, NodeTy* Pred,
- NodeSet& Dst) {
- if (!V.isUnknownOrUndef()) {
- // 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.
- MakeNode(Dst, CastE, Pred, state->bindExpr(CastE, EvalCast(cast<Loc>(V),
- CastE->getType())));
- }
- else
- MakeNode(Dst, CastE, Pred, state->bindExpr(CastE, V));
-}
-
-
void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
NodeSet S1;
QualType T = CastE->getType();
@@ -2070,128 +2047,14 @@
return;
}
-
- // 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) {
NodeTy* N = *I1;
const GRState* state = GetState(N);
SVal V = state->getSVal(Ex);
- ASTContext& C = getContext();
-
- // Unknown?
- if (V.isUnknown()) {
- Dst.Add(N);
- continue;
- }
-
- // Undefined?
- if (V.isUndef())
- goto PassThrough;
-
- // For const casts, just propagate the value.
- if (C.getCanonicalType(T).getUnqualifiedType() ==
- C.getCanonicalType(ExTy).getUnqualifiedType())
- goto PassThrough;
-
- // Check for casts from pointers to integers.
- if (T->isIntegerType() && Loc::IsLocType(ExTy)) {
- VisitCastPointerToInteger(V, state, ExTy, CastE, N, Dst);
- 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.
- V = LV->getLoc();
- MakeNode(Dst, CastE, N, state->bindExpr(CastE, V));
- continue;
- }
-
- goto DispatchCast;
- }
-
- // Just pass through function and block pointers.
- if (ExTy->isBlockPointerType() || ExTy->isFunctionPointerType()) {
- assert(Loc::IsLocType(T));
- goto PassThrough;
- }
-
- // Check for casts from array type to another type.
- if (ExTy->isArrayType()) {
- // We will always decay to a pointer.
- V = StateMgr.ArrayToPointer(cast<Loc>(V));
-
- // Are we casting from an array to a pointer? If so just pass on
- // the decayed value.
- if (T->isPointerType())
- goto PassThrough;
-
- // Are we casting from an array to an integer? If so, cast the decayed
- // pointer value to an integer.
- assert(T->isIntegerType());
- QualType ElemTy = cast<ArrayType>(ExTy)->getElementType();
- QualType PointerTy = getContext().getPointerType(ElemTy);
- VisitCastPointerToInteger(V, state, PointerTy, CastE, N, Dst);
- continue;
- }
-
- // Check for casts from a region to a specific type.
- if (loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(&V)) {
- // FIXME: For TypedViewRegions, we should handle the case where the
- // underlying symbolic pointer is a function pointer or
- // block pointer.
-
- // FIXME: We should handle the case where we strip off view layers to get
- // to a desugared type.
-
- assert(Loc::IsLocType(T));
- // We get a symbolic function pointer for a dereference of a function
- // pointer, but it is of function type. Example:
-
- // struct FPRec {
- // void (*my_func)(int * x);
- // };
- //
- // int bar(int x);
- //
- // int f1_a(struct FPRec* foo) {
- // int x;
- // (*foo->my_func)(&x);
- // return bar(x)+1; // no-warning
- // }
-
- assert(Loc::IsLocType(ExTy) || ExTy->isFunctionType());
-
- const MemRegion* R = RV->getRegion();
- StoreManager& StoreMgr = getStoreManager();
-
- // Delegate to store manager to get the result of casting a region
- // to a different type.
- const StoreManager::CastResult& Res = StoreMgr.CastRegion(state, R, T);
-
- // Inspect the result. If the MemRegion* returned is NULL, this
- // expression evaluates to UnknownVal.
- R = Res.getRegion();
- if (R) { V = loc::MemRegionVal(R); } else { V = UnknownVal(); }
-
- // Generate the new node in the ExplodedGraph.
- MakeNode(Dst, CastE, N, Res.getState()->bindExpr(CastE, V));
- continue;
- }
- // All other cases.
- DispatchCast: {
- MakeNode(Dst, CastE, N, state->bindExpr(CastE,
- EvalCast(V, CastE->getType())));
- continue;
- }
-
- PassThrough: {
- MakeNode(Dst, CastE, N, state->bindExpr(CastE, V));
- }
+ const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
+ state = Res.getState()->bindExpr(CastE, Res.getSVal());
+ MakeNode(Dst, CastE, N, state);
}
}
@@ -3034,17 +2897,19 @@
// The RHS is not Unknown.
// Get the computation type.
- QualType CTy = cast<CompoundAssignOperator>(B)->getComputationResultType();
+ QualType CTy =
+ cast<CompoundAssignOperator>(B)->getComputationResultType();
CTy = getContext().getCanonicalType(CTy);
- QualType CLHSTy = cast<CompoundAssignOperator>(B)->getComputationLHSType();
- CLHSTy = getContext().getCanonicalType(CTy);
+ QualType CLHSTy =
+ cast<CompoundAssignOperator>(B)->getComputationLHSType();
+ CLHSTy = getContext().getCanonicalType(CLHSTy);
QualType LTy = getContext().getCanonicalType(LHS->getType());
QualType RTy = getContext().getCanonicalType(RHS->getType());
// Promote LHS.
- V = EvalCast(V, CLHSTy);
+ llvm::tie(state, V) = SVator.EvalCast(V, state, CLHSTy, LTy);
// Evaluate operands and promote to result type.
if (RightV.isUndef()) {
@@ -3055,8 +2920,10 @@
}
// Compute the result of the operation.
- SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
- B->getType());
+ SVal Result;
+ llvm::tie(state, Result) = SVator.EvalCast(EvalBinOp(state, Op, V,
+ RightV, CTy),
+ state, B->getType(), CTy);
if (Result.isUndef()) {
// The operands were not undefined, but the result is undefined.
@@ -3085,12 +2952,12 @@
LHSVal = ValMgr.getConjuredSymbolVal(B->getRHS(), LTy, Count);
// However, we need to convert the symbol to the computation type.
- Result = (LTy == CTy) ? LHSVal : EvalCast(LHSVal,CTy);
+ llvm::tie(state, Result) = SVator.EvalCast(LHSVal, state, CTy, LTy);
}
else {
// The left-hand side may bind to a different value then the
// computation type.
- LHSVal = (LTy == CTy) ? Result : EvalCast(Result,LTy);
+ llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
}
EvalStore(Dst, B, LHS, *I3, state->bindExpr(B, Result), location,
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 2ea2b88..dc54c8f 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -279,7 +279,8 @@
/// return undefined
/// else
/// return symbolic
- SVal Retrieve(const GRState *state, Loc L, QualType T = QualType());
+ SValuator::CastResult Retrieve(const GRState *state, Loc L,
+ QualType T = QualType());
SVal RetrieveElement(const GRState *state, const ElementRegion *R);
@@ -291,7 +292,8 @@
SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R);
- SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy);
+ SValuator::CastResult CastRetrievedVal(SVal val, const GRState *state,
+ const TypedRegion *R, QualType castTy);
/// Retrieve the values in a struct and return a CompoundVal, used when doing
/// struct copy:
@@ -780,7 +782,8 @@
return true;
}
-SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
+SValuator::CastResult
+RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -788,7 +791,7 @@
// FIXME: Is this even possible? Shouldn't this be treated as a null
// dereference at a higher level?
if (isa<loc::ConcreteInt>(L))
- return UndefinedVal();
+ return SValuator::CastResult(state, UndefinedVal());
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
@@ -799,7 +802,7 @@
// read(p);
// c = *p;
if (isa<AllocaRegion>(MR))
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
if (isa<SymbolicRegion>(MR)) {
ASTContext &Ctx = getContext();
@@ -832,33 +835,33 @@
}
if (RTy->isStructureType())
- return RetrieveStruct(state, R);
+ return SValuator::CastResult(state, RetrieveStruct(state, R));
if (RTy->isArrayType())
- return RetrieveArray(state, R);
+ return SValuator::CastResult(state, RetrieveArray(state, R));
// FIXME: handle Vector types.
if (RTy->isVectorType())
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return CastRetrievedVal(RetrieveField(state, FR), FR, T);
+ return CastRetrievedVal(RetrieveField(state, FR), state, FR, T);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
- return CastRetrievedVal(RetrieveElement(state, ER), ER, T);
+ return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T);
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
- return CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T);
+ return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T);
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
- return CastRetrievedVal(RetrieveVar(state, VR), VR, T);
+ return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T);
RegionBindingsTy B = GetRegionBindings(state->getStore());
RegionBindingsTy::data_type* V = B.lookup(R);
// Check if the region has a binding.
if (V)
- return *V;
+ return SValuator::CastResult(state, *V);
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
@@ -870,7 +873,7 @@
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
// to specific values.
- return UndefinedVal();
+ return SValuator::CastResult(state, UndefinedVal());
}
// If the region is already cast to another type, use that type to create the
@@ -881,7 +884,8 @@
}
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, RTy);
+ return SValuator::CastResult(state,
+ ValMgr.getRegionValueSymbolValOrUnknown(R, RTy));
}
SVal RegionStoreManager::RetrieveElement(const GRState* state,
@@ -1079,7 +1083,7 @@
Field != FieldEnd; ++Field) {
FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
QualType FTy = (*Field)->getType();
- SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy);
+ SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal();
StructVal = getBasicVals().consVals(FieldValue, StructVal);
}
@@ -1099,28 +1103,22 @@
ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
getContext());
QualType ETy = ER->getElementType();
- SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy);
+ SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal();
ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
}
return ValMgr.makeCompoundVal(T, ArrayVal);
}
-SVal RegionStoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
- QualType castTy) {
-
+SValuator::CastResult RegionStoreManager::CastRetrievedVal(SVal V,
+ const GRState *state,
+ const TypedRegion *R,
+ QualType castTy) {
if (castTy.isNull())
- return V;
+ return SValuator::CastResult(state, V);
ASTContext &Ctx = getContext();
- QualType valTy = R->getValueType(Ctx);
- castTy = Ctx.getCanonicalType(castTy);
-
-
- if (valTy == castTy)
- return V;
-
- return ValMgr.getSValuator().EvalCast(V, castTy);
+ return ValMgr.getSValuator().EvalCast(V, state, castTy, R->getValueType(Ctx));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
new file mode 100644
index 0000000..b06b94f
--- /dev/null
+++ b/lib/Analysis/SValuator.cpp
@@ -0,0 +1,123 @@
+// SValuator.cpp - Basic class for all SValuator implementations --*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SValuator, the base class for all (complete) SValuator
+// implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/SValuator.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+using namespace clang;
+
+SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
+ QualType castTy, QualType originalTy){
+
+ if (val.isUnknownOrUndef() || castTy == originalTy)
+ return CastResult(state, val);
+
+ ASTContext &C = ValMgr.getContext();
+
+ // For const casts, just propagate the value.
+ if (C.getCanonicalType(castTy).getUnqualifiedType() ==
+ C.getCanonicalType(originalTy).getUnqualifiedType())
+ return CastResult(state, val);
+
+ // Check for casts from pointers to integers.
+ if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
+ return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+
+ // Check for casts from integers to pointers.
+ if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
+ if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ // Just unpackage the lval and return it.
+ return CastResult(state, LV->getLoc());
+ }
+
+ goto DispatchCast;
+ }
+
+ // Just pass through function and block pointers.
+ if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
+ assert(Loc::IsLocType(castTy));
+ return CastResult(state, val);
+ }
+
+ // Check for casts from array type to another type.
+ if (originalTy->isArrayType()) {
+ // We will always decay to a pointer.
+ val = ValMgr.getStateManager().ArrayToPointer(cast<Loc>(val));
+
+ // Are we casting from an array to a pointer? If so just pass on
+ // the decayed value.
+ if (castTy->isPointerType())
+ return CastResult(state, val);
+
+ // Are we casting from an array to an integer? If so, cast the decayed
+ // pointer value to an integer.
+ assert(castTy->isIntegerType());
+
+ // FIXME: Keep these here for now in case we decide soon that we
+ // need the original decayed type.
+ // QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
+ // QualType pointerTy = C.getPointerType(elemTy);
+ return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+ }
+
+ // Check for casts from a region to a specific type.
+ if (const MemRegion *R = val.getAsRegion()) {
+ // FIXME: For TypedViewRegions, we should handle the case where the
+ // underlying symbolic pointer is a function pointer or
+ // block pointer.
+
+ // FIXME: We should handle the case where we strip off view layers to get
+ // to a desugared type.
+
+ assert(Loc::IsLocType(castTy));
+ // We get a symbolic function pointer for a dereference of a function
+ // pointer, but it is of function type. Example:
+
+ // struct FPRec {
+ // void (*my_func)(int * x);
+ // };
+ //
+ // int bar(int x);
+ //
+ // int f1_a(struct FPRec* foo) {
+ // int x;
+ // (*foo->my_func)(&x);
+ // return bar(x)+1; // no-warning
+ // }
+
+ assert(Loc::IsLocType(originalTy) || originalTy->isFunctionType() ||
+ originalTy->isBlockPointerType());
+
+ StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager();
+
+ // Delegate to store manager to get the result of casting a region
+ // to a different type.
+ const StoreManager::CastResult& Res = storeMgr.CastRegion(state, R, castTy);
+
+ // Inspect the result. If the MemRegion* returned is NULL, this
+ // expression evaluates to UnknownVal.
+ R = Res.getRegion();
+
+ if (R)
+ return CastResult(Res.getState(), loc::MemRegionVal(R));
+
+ return CastResult(Res.getState(), UnknownVal());
+ }
+
+ // All other cases.
+DispatchCast:
+ return CastResult(state,
+ isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
+ : EvalCastNL(cast<NonLoc>(val), castTy));
+}
\ No newline at end of file
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 7462fe6..9850b2e 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -19,12 +19,14 @@
namespace {
class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
+protected:
+ virtual SVal EvalCastNL(NonLoc val, QualType castTy);
+ virtual SVal EvalCastL(Loc val, QualType castTy);
+
public:
SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {}
virtual ~SimpleSValuator() {}
- virtual SVal EvalCastNL(NonLoc val, QualType castTy);
- virtual SVal EvalCastL(Loc val, QualType castTy);
virtual SVal EvalMinus(NonLoc val);
virtual SVal EvalComplement(NonLoc val);
virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs,
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp
index 658dfa1..ee6b5cb 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Analysis/ValueManager.cpp
@@ -56,6 +56,9 @@
SVal ValueManager::convertToArrayIndex(SVal V) {
+ if (V.isUnknownOrUndef())
+ return V;
+
// Common case: we have an appropriately sized integer.
if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&V)) {
const llvm::APSInt& I = CI->getValue();
@@ -63,7 +66,7 @@
return V;
}
- return SVator->EvalCast(V, ArrayIndexTy);
+ return SVator->EvalCastNL(cast<NonLoc>(V), ArrayIndexTy);
}
SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, QualType T) {