Skip to content

Commit

Permalink
Lower bounds for double check to 53
Browse files Browse the repository at this point in the history
  • Loading branch information
markbenvenuto committed Jul 23, 2024
1 parent 3209492 commit b064105
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 120 deletions.
7 changes: 5 additions & 2 deletions src/mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ bool mc_canUsePrecisionModeDouble(double min,
return false;
}

if (*maxBitsOut >= 64) {
// Integers between -2^53 and 2^53 can be exactly represented. Outside this range, doubles lose precision by a
// multiple of 2^(n-52) where n = #bits. We disallow users from using precision mode when the bounds exceed 2^53 to
// prevent the users from being surprised by how floating point math works.
if (*maxBitsOut >= 53) {
return false;
}

Expand Down Expand Up @@ -339,7 +342,7 @@ bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args,
}

CLIENT_ERR("The domain of double values specified by the min, max, and precision cannot be represented in "
"fewer than 64 bits. min: %g, max: %g, precision: %" PRIu32,
"fewer than 53 bits. min: %g, max: %g, precision: %" PRIu32,
args.min.value,
args.max.value,
args.precision.value);
Expand Down
135 changes: 17 additions & 118 deletions test/test-mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,7 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) {
.max = OPT_DOUBLE_C(5),
.min = OPT_DOUBLE_C(0),
.precision = OPT_U32_C(16),
.expect = 31415926535890000,
.expectMax = OPT_U64_C(72057594037927935)},
.expectError = "The domain of double values specified by the min"},
{.value = -5,
.max = OPT_DOUBLE_C(-1),
.min = OPT_DOUBLE_C(-10),
Expand Down Expand Up @@ -464,77 +463,31 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) {
.max = OPT_DOUBLE_C(10E-30),
.min = OPT_DOUBLE_C(1E-30),
.precision = OPT_U32_C(35),
// Applying min/max/precision result in a domain needing >= 64 bits to represent.
// Applying min/max/precision result in a domain needing >= 53 bits to represent.
// For range v2, expect an error.
.expectError = "Invalid upper bounds for double precision."},
.expectError = "Invalid upper bounds for double precision"},
{.value = 1E-30,
.max = OPT_DOUBLE_C(10E-30),
.min = OPT_DOUBLE_C(1E-30),
.precision = OPT_U32_C(35),
// Applying min/max/precision result in a domain needing >= 64 bits to represent.
// Applying min/max/precision result in a domain needing >= 53 bits to represent.
// For range v2, expect an error.
.expectError = "Invalid upper bounds for double precision."},
.expectError = "Invalid upper bounds for double precision"},
/* Test max and min integer bounds for doubles */
{.value = DOUBLE_MIN_SAFE_INT,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 0,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = DOUBLE_MIN_SAFE_INT + 1,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 1,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 0,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740992,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 1,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740993,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 2,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740994,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 3,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740995,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 4,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740996,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 5,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740997,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = 0,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
.precision = OPT_U32_C(0),
.expect = 9007199254740992,
.expectMax = OPT_U64_C(36028797018963967)},
{.value = DOUBLE_MAX_SAFE_INT,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
.min = OPT_DOUBLE_C(DOUBLE_MIN_SAFE_INT),
// Applying min/max/precision result in a domain needing >= 53 bits to represent.
// For range v2, expect an error.
.expectError = "The domain of double values specified by the min"},
{.value = 900719925474099.6,
.max = OPT_DOUBLE_C(900719925474100.0),
.min = OPT_DOUBLE_C(900719925474099.0),
.precision = OPT_U32_C(0),
.expect = 18014398509481984,
.expectMax = OPT_U64_C(36028797018963967)},
.expect = 0,
.expectMax = OPT_U64_C(1)},
// 2^52
// The expected values increase by 4503599627370496 * 2^(i-52) + j
// i.e. the gaps between integers as the exponent increases since doubles lose precision as
Expand All @@ -543,64 +496,10 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) {
.max = OPT_DOUBLE_C(4503599627370496),
.min = OPT_DOUBLE_C(-4503599627370496),
.precision = OPT_U32_C(0),
.expect = 4503599627370496,
.expectMax = OPT_U64_C(18014398509481983)},
// 2^53
{.value = 1,
.max = OPT_DOUBLE_C(9007199254740992),
.min = OPT_DOUBLE_C(-9007199254740992),
.precision = OPT_U32_C(0),
.expect = 9007199254740993,
.expectMax = OPT_U64_C(36028797018963967)},
// 2^54
{.value = 2,
.max = OPT_DOUBLE_C(18014398509481984),
.min = OPT_DOUBLE_C(-18014398509481984),
.precision = OPT_U32_C(0),
.expect = 18014398509481986,
.expectMax = OPT_U64_C(72057594037927935)},
// 2^55
{.value = 3,
.max = OPT_DOUBLE_C(36028797018963968),
.min = OPT_DOUBLE_C(-36028797018963968),
.precision = OPT_U32_C(0),
.expect = 36028797018963971,
.expectMax = OPT_U64_C(144115188075855871)},
// 2^56
{.value = 4,
.max = OPT_DOUBLE_C(72057594037927936),
.min = OPT_DOUBLE_C(-72057594037927936),
.precision = OPT_U32_C(0),
.expect = 72057594037927940,
.expectMax = OPT_U64_C(288230376151711743)},
// 2^57
{.value = 1,
.max = OPT_DOUBLE_C(144115188075855872),
.min = OPT_DOUBLE_C(-144115188075855872),
.precision = OPT_U32_C(0),
.expect = 144115188075855873,
.expectMax = OPT_U64_C(576460752303423487)},
// 2^58
{.value = 2,
.max = OPT_DOUBLE_C(288230376151711744),
.min = OPT_DOUBLE_C(-288230376151711744),
.precision = OPT_U32_C(0),
.expect = 288230376151711746,
.expectMax = OPT_U64_C(1152921504606846975)},
// 2^59
{.value = 3,
.max = OPT_DOUBLE_C(576460752303423488),
.min = OPT_DOUBLE_C(-576460752303423488),
.precision = OPT_U32_C(0),
.expect = 576460752303423491,
.expectMax = OPT_U64_C(2305843009213693951)},
// 2^60
{.value = 4,
.max = OPT_DOUBLE_C(1152921504606846976),
.min = OPT_DOUBLE_C(-1152921504606846976),
.precision = OPT_U32_C(0),
.expect = 1152921504606846980,
.expectMax = OPT_U64_C(4611686018427387903)},
.expect = 0,
// Applying min/max/precision result in a domain needing >= 53 bits to represent.
// For range v2, expect an error.
.expectError = "The domain of double values specified by the min"},
/* Test cases copied from Double_Bounds_Precision ... end */
{.value = -1,
.min = OPT_DOUBLE_C(0),
Expand Down

0 comments on commit b064105

Please sign in to comment.