From c52cec7e518feb30ec01bc0a978b620f8d9462ab Mon Sep 17 00:00:00 2001 From: Eli Fidler Date: Tue, 31 May 2016 13:46:04 -0400 Subject: [PATCH] fix undefined double to uint64_t cast note that std::numeric_limits::max() and std::numeric_limits::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' --- include/rapidjson/document.h | 9 +++++++-- 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 d286eb1..f1857f5 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -23,6 +23,7 @@ #include "memorystream.h" #include "encodedstream.h" #include // placement new +#include #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH @@ -952,12 +953,16 @@ public: if (IsUint64()) { uint64_t u = GetUint64(); volatile double d = static_cast(u); - return static_cast(d) == u; + return (d >= 0.0) + && (d < static_cast(std::numeric_limits::max())) + && (u == static_cast(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast(i); - return static_cast< int64_t>(d) == i; + return (d >= static_cast(std::numeric_limits::min())) + && (d < static_cast(std::numeric_limits::max())) + && (i == static_cast(d)); } return true; // double, int, uint are always lossless } diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 430a828..fefc001 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(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble()); - EXPECT_FALSE(Value(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)).IsLosslessDouble()); + EXPECT_FALSE(Value(static_cast(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble()); // INT64_MAX + EXPECT_FALSE(Value(-static_cast(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble()); // -INT64_MAX + EXPECT_TRUE(Value(-static_cast(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) {