@@ -87,7 +87,8 @@ template <typename T, typename U>
87
87
static inline bool InRange (double d, T min, U max) {
88
88
// The casts can lose precision, but we are looking only for
89
89
// an approximate range. Might fail on edge cases though. ~cdunn
90
- return d >= static_cast <double >(min) && d <= static_cast <double >(max);
90
+ return d >= static_cast <double >(min) && d <= static_cast <double >(max) &&
91
+ !(static_cast <U>(d) == min && d != static_cast <double >(min));
91
92
}
92
93
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
93
94
static inline double integerToDouble (Json::UInt64 value) {
@@ -101,7 +102,8 @@ template <typename T> static inline double integerToDouble(T value) {
101
102
102
103
template <typename T, typename U>
103
104
static inline bool InRange (double d, T min, U max) {
104
- return d >= integerToDouble (min) && d <= integerToDouble (max);
105
+ return d >= integerToDouble (min) && d <= integerToDouble (max) &&
106
+ !(static_cast <U>(d) == min && d != integerToDouble (min));
105
107
}
106
108
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
107
109
@@ -705,6 +707,11 @@ Value::Int64 Value::asInt64() const {
705
707
JSON_ASSERT_MESSAGE (isInt64 (), " LargestUInt out of Int64 range" );
706
708
return Int64 (value_.uint_ );
707
709
case realValue:
710
+ // If the double value is in proximity to minInt64, it will be rounded to
711
+ // minInt64. The correct value in this scenario is indeterminable
712
+ JSON_ASSERT_MESSAGE (
713
+ value_.real_ != minInt64,
714
+ " Double value is minInt64, precise value cannot be determined" );
708
715
JSON_ASSERT_MESSAGE (InRange (value_.real_ , minInt64, maxInt64),
709
716
" double out of Int64 range" );
710
717
return Int64 (value_.real_ );
@@ -1311,8 +1318,12 @@ bool Value::isInt64() const {
1311
1318
// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
1312
1319
// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
1313
1320
// require the value to be strictly less than the limit.
1314
- return value_.real_ >= double (minInt64) &&
1315
- value_.real_ < double (maxInt64) && IsIntegral (value_.real_ );
1321
+ // minInt64 is -2^63 which can be represented as a double, but since double
1322
+ // values in its proximity are also rounded to -2^63, we require the value
1323
+ // to be strictly greater than the limit to avoid returning 'true' for
1324
+ // values that are not in the range
1325
+ return value_.real_ > double (minInt64) && value_.real_ < double (maxInt64) &&
1326
+ IsIntegral (value_.real_ );
1316
1327
default :
1317
1328
break ;
1318
1329
}
@@ -1350,7 +1361,11 @@ bool Value::isIntegral() const {
1350
1361
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1351
1362
// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1352
1363
// require the value to be strictly less than the limit.
1353
- return value_.real_ >= double (minInt64) &&
1364
+ // minInt64 is -2^63 which can be represented as a double, but since double
1365
+ // values in its proximity are also rounded to -2^63, we require the value
1366
+ // to be strictly greater than the limit to avoid returning 'true' for
1367
+ // values that are not in the range
1368
+ return value_.real_ > double (minInt64) &&
1354
1369
value_.real_ < maxUInt64AsDouble && IsIntegral (value_.real_ );
1355
1370
#else
1356
1371
return value_.real_ >= minInt && value_.real_ <= maxUInt &&
0 commit comments