Skip to content

Commit

Permalink
Add checks for min/max values themselves that lose precision
Browse files Browse the repository at this point in the history
  • Loading branch information
markbenvenuto committed Jul 24, 2024
1 parent b064105 commit cfa0e57
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 16 deletions.
8 changes: 5 additions & 3 deletions src/mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ bool mc_getTypeInfo64(mc_getTypeInfo64_args_t args, mc_OSTType_Int64 *out, mongo
}

#define exp10Double(x) pow(10, x)
#define SCALED_DOUBLE_BOUNDS 9223372036854775807.0 // 2^63 - 1
#define SCALED_DOUBLE_BOUNDS 9007199254740992.0 // 2^53
#define UINT_64_MAX 18446744073709551615ull

uint64_t subtract_int64_t(int64_t max, int64_t min) {
Expand Down Expand Up @@ -229,13 +229,15 @@ bool mc_canUsePrecisionModeDouble(double min,
}

if (fabs(scaled_max) >= SCALED_DOUBLE_BOUNDS) {
CLIENT_ERR("Invalid upper bounds for double precision. abs(max) must be less than 9223372036854775807. max: %g",
CLIENT_ERR("Invalid upper bounds for double precision. abs(max * 10^precision) must be less than "
"9007199254740992. max: %g",
max);
return false;
}

if (fabs(scaled_min) >= SCALED_DOUBLE_BOUNDS) {
CLIENT_ERR("Invalid lower bounds for double precision. abs(min) must be less than 9223372036854775807. min: %g",
CLIENT_ERR("Invalid lower bounds for double precision. abs(min * 10^precision) must be less than "
"9007199254740992. min: %g",
min);
return false;
}
Expand Down
37 changes: 24 additions & 13 deletions test/test-mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,25 +223,25 @@ static void _test_canUsePrecisionModeDouble(_mongocrypt_tester_t *tester) {
CAN_USE_PRECISION_MODE(0.0, 16.0, 0, true, 5);
// 2^53 + 1 is where double starts to lose precision, so we need to ensure that we get the
// correct value for max_bits out.
CAN_USE_PRECISION_MODE(1.0, 9007199254740992.0, 0, true, 53);
CAN_USE_PRECISION_MODE(0.0, 9007199254740992.0, 0, true, 54);
CAN_USE_PRECISION_MODE_ERRORS(1.0, 9007199254740992.0, 0, "Invalid upper bounds for double precision. abs");
CAN_USE_PRECISION_MODE_ERRORS(0.0, 9007199254740992.0, 0, "Invalid upper bounds for double precision. abs");

CAN_USE_PRECISION_MODE(2.718281, 314.159265, 6, true, 29);

CAN_USE_PRECISION_MODE(-1000000000.0, 9223372036844775424.0, 0, false, 64);
CAN_USE_PRECISION_MODE_ERRORS(-1000000000.0,
9223372036844775424.0,
0,
"Invalid upper bounds for double precision. abs");

CAN_USE_PRECISION_MODE_ERRORS(2.710000, 314.150000, 2, "Invalid upper bounds for double precision. Digits after");
CAN_USE_PRECISION_MODE_ERRORS(314.150000, 350.0, 2, "Invalid lower bounds for double precision. Digits after");

CAN_USE_PRECISION_MODE_ERRORS((double)9007199254740992,
INT_64_MAX_DOUBLE,
0,
"Invalid upper bounds for double precision. abs(max) must");
CAN_USE_PRECISION_MODE_ERRORS(-1 * INT_64_MAX_DOUBLE,
-1 * (double)9007199254740992,
0,
"Invalid lower bounds for double precision. abs(min) must");
CAN_USE_PRECISION_MODE_ERRORS(-92233720368547.0, 92233720368547.0, 5, "Invalid value for precision.");
"Invalid upper bounds for double precision. abs(max");
CAN_USE_PRECISION_MODE_ERRORS(-1 * INT_64_MAX_DOUBLE, 1.0, 0, "Invalid lower bounds for double precision. abs(min");
CAN_USE_PRECISION_MODE_ERRORS(-92233720368547.0, 92233720368547.0, 5, "Invalid upper bounds for double");

#undef CAN_USE_PRECISION_MODE
#undef CAN_USE_PRECISION_MODE_ERRORS
Expand Down Expand Up @@ -414,7 +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),
.expectError = "The domain of double values specified by the min"},
.expectError = "Invalid upper bounds for double precision"},
{.value = -5,
.max = OPT_DOUBLE_C(-1),
.min = OPT_DOUBLE_C(-10),
Expand Down Expand Up @@ -465,14 +465,14 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) {
.precision = OPT_U32_C(35),
// 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. Digits"},
{.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 >= 53 bits to represent.
// For range v2, expect an error.
.expectError = "Invalid upper bounds for double precision"},
.expectError = "Invalid upper bounds for double precision. Digits"},
/* Test max and min integer bounds for doubles */
{.value = DOUBLE_MIN_SAFE_INT,
.max = OPT_DOUBLE_C(DOUBLE_MAX_SAFE_INT),
Expand All @@ -481,13 +481,24 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) {
.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"},
.expectError = "Invalid upper bounds for double precision. abs"},
{.value = 900719925474099.6,
.max = OPT_DOUBLE_C(900719925474100.0),
.min = OPT_DOUBLE_C(900719925474099.0),
.precision = OPT_U32_C(0),
.expect = 0,
.expectMax = OPT_U64_C(1)},
// Domain size is small but min/max * 10^precision loses precision.
{.value = 900719925474099.6,
.max = OPT_DOUBLE_C(900719925474100.0),
.min = OPT_DOUBLE_C(900719925474099.0),
.precision = OPT_U32_C(1),
.expectError = "Invalid upper bounds for double precision. abs"},
{.value = -900719925474099.6,
.max = OPT_DOUBLE_C(-900719925474099.0),
.min = OPT_DOUBLE_C(-900719925474100.0),
.precision = OPT_U32_C(1),
.expectError = "Invalid lower bounds for double precision. abs"},
// 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 Down

0 comments on commit cfa0e57

Please sign in to comment.