diff options
author | Eli Fidler <efidler@topologyinc.com> | 2016-05-31 20:46:04 +0300 |
---|---|---|
committer | Eli Fidler <efidler@topologyinc.com> | 2016-06-14 17:01:41 +0300 |
commit | c52cec7e518feb30ec01bc0a978b620f8d9462ab (patch) | |
tree | 885f7cc533cff36bae5018cb29eb138416db25b6 | |
parent | 05f0592b34cb943e7c96b8767d716431a3d9eaef (diff) |
fix undefined double to uint64_t cast
note that std::numeric_limits<uint64_t>::max() and
std::numeric_limits<int64_t>::max() aren't exactly representable in a
double, so we need to be strictly less to be definitely lossless
UBSAN gave during Value.IsLosslessDouble test:
include/rapidjson/document.h:955:42: runtime error: value 1.84467e+19 is outside the range of representable values of type 'unsigned long'
-rw-r--r-- | include/rapidjson/document.h | 9 | ||||
-rw-r--r-- | test/unittest/valuetest.cpp | 16 |
2 files changed, 21 insertions, 4 deletions
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index d286eb1e..f1857f5c 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -23,6 +23,7 @@ #include "memorystream.h" #include "encodedstream.h" #include <new> // placement new +#include <limits> #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH @@ -952,12 +953,16 @@ public: if (IsUint64()) { uint64_t u = GetUint64(); volatile double d = static_cast<double>(u); - return static_cast<uint64_t>(d) == u; + return (d >= 0.0) + && (d < static_cast<double>(std::numeric_limits<uint64_t>::max())) + && (u == static_cast<uint64_t>(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast<double>(i); - return static_cast< int64_t>(d) == i; + return (d >= static_cast<double>(std::numeric_limits<int64_t>::min())) + && (d < static_cast<double>(std::numeric_limits<int64_t>::max())) + && (i == static_cast<int64_t>(d)); } return true; // double, int, uint are always lossless } diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 430a828a..fefc001d 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -673,6 +673,7 @@ TEST(Value, Float) { } TEST(Value, IsLosslessDouble) { + EXPECT_TRUE(Value(0.0).IsLosslessDouble()); EXPECT_TRUE(Value(12.34).IsLosslessDouble()); EXPECT_TRUE(Value(-123).IsLosslessDouble()); EXPECT_TRUE(Value(2147483648u).IsLosslessDouble()); @@ -681,8 +682,19 @@ TEST(Value, IsLosslessDouble) { EXPECT_TRUE(Value(RAPIDJSON_UINT64_C2(0xA0000000, 0x00000000)).IsLosslessDouble()); #endif - EXPECT_FALSE(Value(-static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble()); - EXPECT_FALSE(Value(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)).IsLosslessDouble()); + EXPECT_FALSE(Value(static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble()); // INT64_MAX + EXPECT_FALSE(Value(-static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble()); // -INT64_MAX + EXPECT_TRUE(Value(-static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF)) - 1).IsLosslessDouble()); // INT64_MIN + EXPECT_FALSE(Value(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)).IsLosslessDouble()); // UINT64_MAX + + EXPECT_TRUE(Value(3.4028234e38f).IsLosslessDouble()); // FLT_MAX + EXPECT_TRUE(Value(-3.4028234e38f).IsLosslessDouble()); // -FLT_MAX + EXPECT_TRUE(Value(1.17549435e-38f).IsLosslessDouble()); // FLT_MIN + EXPECT_TRUE(Value(-1.17549435e-38f).IsLosslessDouble()); // -FLT_MIN + EXPECT_TRUE(Value(1.7976931348623157e+308).IsLosslessDouble()); // DBL_MAX + EXPECT_TRUE(Value(-1.7976931348623157e+308).IsLosslessDouble()); // -DBL_MAX + EXPECT_TRUE(Value(2.2250738585072014e-308).IsLosslessDouble()); // DBL_MIN + EXPECT_TRUE(Value(-2.2250738585072014e-308).IsLosslessDouble()); // -DBL_MIN } TEST(Value, IsLosslessFloat) { |