Commit 280ed260 authored by Ng Zhi An's avatar Ng Zhi An Committed by Commit Bot

Fix conversion range check for floating-point to unsigned

When converting floating-point to any integer type, the fractional part
is discarded, so any value in the range (-1.0,-0.00) (exclusive) will
truncate to -0.0, and so will fit in an unsigned destination type.

See https://en.cppreference.com/w/cpp/language/implicit_conversion#Floating.E2.80.93integral_conversions.

Change-Id: Id8a5263d486cc3cd25670da27c417c66e28fccdd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2488717Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#819633}
parent 31c2595e
......@@ -378,9 +378,17 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
using SrcLimits = std::numeric_limits<Src>;
using DstLimits = NarrowingRange<Dst, Src, Bounds>;
using Promotion = decltype(Src() + Dst());
bool ge_zero = false;
// Converting floating-point to integer will discard fractional part, so
// values in (-1.0, -0.0) will truncate to 0 and fit in Dst.
if (std::is_floating_point<Src>::value) {
ge_zero = value > Src(-1);
} else {
ge_zero = value >= Src(0);
}
return RangeCheck(
value >= Src(0) && (DstLimits::lowest() == 0 ||
static_cast<Dst>(value) >= DstLimits::lowest()),
ge_zero && (DstLimits::lowest() == 0 ||
static_cast<Dst>(value) >= DstLimits::lowest()),
static_cast<Promotion>(SrcLimits::max()) <=
static_cast<Promotion>(DstLimits::max()) ||
static_cast<Promotion>(value) <=
......
......@@ -1535,6 +1535,11 @@ TEST(SafeNumerics, IsValueInRangeForNumericType) {
EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
std::numeric_limits<int64_t>::lowest()));
// Converting to integer types will discard the fractional part first, so -0.9
// will be truncated to -0.0.
EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(-0.9));
EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1.0));
EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0));
EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1));
EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2));
......@@ -1569,6 +1574,11 @@ TEST(SafeNumerics, IsValueInRangeForNumericType) {
EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
std::numeric_limits<int64_t>::lowest()));
// Converting to integer types will discard the fractional part first, so -0.9
// will be truncated to -0.0.
EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(-0.9));
EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1.0));
EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0));
EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1));
EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment