Commit c52cec7e authored by Eli Fidler's avatar Eli Fidler

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'
parent 05f0592b
......@@ -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
}
......
......@@ -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) {
......
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