diff options
author | Justin Seyster <justin.seyster@mongodb.com> | 2019-03-27 17:16:13 -0400 |
---|---|---|
committer | Justin Seyster <justin.seyster@mongodb.com> | 2019-04-03 15:16:15 -0400 |
commit | f2ab9fa71aabf110b67c28131241de6a27a3f09e (patch) | |
tree | 66eb289716ef0c4899a6538426afed41f7fd8da8 /src/mongo/bson/bsonelement_test.cpp | |
parent | d3b98acb26920c94079ebd922b76dddf67d580c0 (diff) | |
download | mongo-f2ab9fa71aabf110b67c28131241de6a27a3f09e.tar.gz |
SERVER-38623 Make safeNumberLongForHash consistent on all platforms
Previously, the hash function for double values relied on undefined
behavior when computing the hash for 2^63, meaning that it could give
different results on different platforms. Almost all platforms we
support returned -2^63 as the result of safeNumberLongForHash when the
input was 2^63, so this patch makes that the official result. Now,
safeNumberLongForHash will explicitly convert 2^63 to -2^63 on _all_
platforms without invoking any undefined behavior.
Note that this does not change our guidance that using a hashed index
for a field containing a floating point value greater than 2^53 is
unsupported:
https://docs.mongodb.com/manual/core/index-hashed/#considerations
Diffstat (limited to 'src/mongo/bson/bsonelement_test.cpp')
-rw-r--r-- | src/mongo/bson/bsonelement_test.cpp | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/src/mongo/bson/bsonelement_test.cpp b/src/mongo/bson/bsonelement_test.cpp index 27f51039245..d8f311450fd 100644 --- a/src/mongo/bson/bsonelement_test.cpp +++ b/src/mongo/bson/bsonelement_test.cpp @@ -138,12 +138,19 @@ TEST(BSONElement, SafeNumberLongPositiveBound) { << "positiveInfinity" << std::numeric_limits<double>::infinity()); - // The numberLongForHash() function clamps kLongLongMaxPlusOneAsDouble to the max 64-bit value + // kLongLongMaxPlusOneAsDouble is the least double value that will overflow a 64-bit signed + // two's-complement integer. Historically, converting this value with safeNumberLong() would + // return the result of casting to double with a C-style cast. That operation is undefined + // because of the overflow, but on most platforms we support, it returned the min 64-bit value + // (-2^63). The safeNumberLongForHash() function should preserve that behavior indefinitely for + // compatibility with on-disk data. + ASSERT_EQ(obj["kLongLongMaxPlusOneAsDouble"].safeNumberLongForHash(), + std::numeric_limits<long long>::lowest()); + + // The safeNumberLong() function clamps kLongLongMaxPlusOneAsDouble to the max 64-bit value // (2^63 - 1). ASSERT_EQ(obj["kLongLongMaxPlusOneAsDouble"].safeNumberLong(), std::numeric_limits<long long>::max()); - // The safeNumberLongForHash() function will return -2^63, but we don't test it here, because - // the overflowing cast that it uses can trigger UBSan // One quantum below kLongLongMaxPlusOneAsDouble is the largest double that safely converts to a // 64-bit signed two-s complement integer. Both safeNumberLong() and safeNumberLongForHash() |