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/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,