}
SVal evalCast(SVal val, QualType castTy, QualType originalType);
-
+
+ // Handles casts of type CK_IntegralCast.
+ SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,
+ QualType originalType);
+
virtual SVal evalMinus(NonLoc val) = 0;
virtual SVal evalComplement(NonLoc val) = 0;
case CK_ArrayToPointerDecay:
case CK_BitCast:
case CK_AddressSpaceConversion:
- case CK_IntegralCast:
case CK_NullToPointer:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
Bldr.generateNode(CastE, Pred, state);
continue;
}
+ case CK_IntegralCast: {
+ // Delegate to SValBuilder to process.
+ SVal V = state->getSVal(Ex, LCtx);
+ V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
// For DerivedToBase cast, delegate to the store manager.
return true;
}
+// Handles casts of type CK_IntegralCast.
+// At the moment, this function will redirect to evalCast, except when the range
+// of the original value is known to be greater than the max of the target type.
+SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val,
+ QualType castTy, QualType originalTy) {
+
+ // No truncations if target type is big enough.
+ if (getContext().getTypeSize(castTy) >= getContext().getTypeSize(originalTy))
+ return evalCast(val, castTy, originalTy);
+
+ const SymExpr *se = val.getAsSymbolicExpression();
+ if (!se) // Let evalCast handle non symbolic expressions.
+ return evalCast(val, castTy, originalTy);
+
+ // Find the maximum value of the target type.
+ APSIntType ToType(getContext().getTypeSize(castTy),
+ castTy->isUnsignedIntegerType());
+ llvm::APSInt ToTypeMax = ToType.getMaxValue();
+ NonLoc ToTypeMaxVal =
+ makeIntVal(ToTypeMax.isUnsigned() ? ToTypeMax.getZExtValue()
+ : ToTypeMax.getSExtValue(),
+ castTy)
+ .castAs<NonLoc>();
+ // Check the range of the symbol being casted against the maximum value of the
+ // target type.
+ NonLoc FromVal = val.castAs<NonLoc>();
+ QualType CmpTy = getConditionType();
+ NonLoc CompVal =
+ evalBinOpNN(state, BO_LT, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>();
+ ProgramStateRef IsNotTruncated, IsTruncated;
+ std::tie(IsNotTruncated, IsTruncated) = state->assume(CompVal);
+ if (!IsNotTruncated && IsTruncated) {
+ // Symbol is truncated so we evaluate it as a cast.
+ NonLoc CastVal = makeNonLoc(se, originalTy, castTy);
+ return CastVal;
+ }
+ return evalCast(val, castTy, originalTy);
+}
+
// FIXME: should rewrite according to the cast kind.
SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
castTy = Context.getCanonicalType(castTy);
--- /dev/null
+// This test checks that intersecting ranges does not cause 'system is over constrained' assertions in the case of eg: 32 bits unsigned integers getting their range from 64 bits signed integers.
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
+
+void clang_analyzer_warnIfReached();
+
+void f1(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0) // because of foo range, index is in range [0; UINT_MAX]
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f2(unsigned long foo)
+{
+ int index = -1;
+ if (index < foo) index = foo; // index equals ULONG_MAX
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // no-warning
+}
+
+void f3(unsigned long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f4(long foo)
+{
+ int index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f5(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index == -1)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f6(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index == -1)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f7(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1 == 0) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f9(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1L == 0L) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f10(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0L)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f12(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1UL == 0L) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f14(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ long bar = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f15(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ unsigned int tmp = index + 1;
+ if (tmp == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}