Skip to content

Commit

Permalink
MONGOCRYPT-695 Remove upper bound assertions on FLE2 range precision (#…
Browse files Browse the repository at this point in the history
…858)

* Remove precision assertions for decimal and double
* Error if precision exceeds INT32_MAX
* Error if precision results in an infinite double/decimal
---------

Co-authored-by: Kevin Albertson <[email protected]>
  • Loading branch information
adriandole and kevinAlbs authored Jul 22, 2024
1 parent 14ccd9c commit 6dff2a8
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 14 deletions.
38 changes: 26 additions & 12 deletions src/mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,19 @@ bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args,
}
}

if (args.precision.set) {
if (args.precision.value > INT32_MAX) {
CLIENT_ERR("Precision cannot be greater than %" PRId32 ", got %" PRIu32, INT32_MAX, args.precision.value);
return false;
}

double scaled = exp10Double(args.precision.value);
if (!mc_isfinite(scaled)) {
CLIENT_ERR("Precision is too large and cannot be used to calculate the scaled range bounds");
return false;
}
}

const bool is_neg = args.value < 0.0;

// Map negative 0 to zero so sign bit is 0.
Expand All @@ -241,12 +254,6 @@ bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args,
bool use_precision_mode = false;
uint32_t bits_range;
if (args.precision.set) {
// Subnormal representations can support up to 5x10^-324 as a number
if (args.precision.value > 324) {
CLIENT_ERR("Precision must be between 0 and 324 inclusive, got: %" PRIu32, args.precision.value);
return false;
}

use_precision_mode =
mc_canUsePrecisionModeDouble(args.min.value, args.max.value, args.precision.value, &bits_range);
if (!use_precision_mode && use_range_v2) {
Expand Down Expand Up @@ -393,6 +400,19 @@ bool mc_getTypeInfoDecimal128(mc_getTypeInfoDecimal128_args_t args,
return false;
}

if (args.precision.set) {
if (args.precision.value > INT32_MAX) {
CLIENT_ERR("Precision cannot be greater than %" PRId32 ", got %" PRIu32, INT32_MAX, args.precision.value);
return false;
}

mc_dec128 scaled = mc_dec128_scale(MC_DEC128(1), args.precision.value);
if (!mc_dec128_is_finite(scaled)) {
CLIENT_ERR("Precision is too large and cannot be used to calculate the scaled range bounds");
return false;
}
}

// We only accept normal numbers
if (mc_dec128_is_inf(args.value) || mc_dec128_is_nan(args.value)) {
CLIENT_ERR("Infinity and Nan Decimal128 values are not supported.");
Expand Down Expand Up @@ -438,12 +458,6 @@ bool mc_getTypeInfoDecimal128(mc_getTypeInfoDecimal128_args_t args,
// The number of bits required to hold the result (used for precision mode)
uint32_t bits_range = 0;
if (args.precision.set) {
// Subnormal representations can support up to 5x10^-6182 as a number
if (args.precision.value > 6182) {
CLIENT_ERR("Precision must be between 0 and 6182 inclusive, got: %" PRIu32, args.precision.value);
return false;
}

use_precision_mode =
mc_canUsePrecisionModeDecimal(args.min.value, args.max.value, args.precision.value, &bits_range);

Expand Down
29 changes: 27 additions & 2 deletions test/test-mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <float.h> // DBL_MAX
#include <math.h> // INFINITY, NAN
#include <stdint.h>

typedef struct {
mc_getTypeInfo32_args_t args;
Expand Down Expand Up @@ -435,7 +436,20 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) {
.min = OPT_DOUBLE_C(0),
.max = OPT_DOUBLE_C(201),
.precision = OPT_U32_C(1),
.expectError = "less than or equal to the maximum value"}};
.expectError = "less than or equal to the maximum value"},
{// Expect error due to precision exceeding INT32_MAX.
.value = 1,
.min = OPT_DOUBLE_C(1),
.max = OPT_DOUBLE_C(2),
.precision = OPT_U32_C((uint32_t)INT32_MAX + 1),
.expectError = "Precision cannot be greater than 2147483647"},
{// Expect error due to precision exceeding max finite double.
// The largest double value is 1.7976931348623157x10^308. 10^309 results in infinity.
.value = 1,
.min = OPT_DOUBLE_C(0),
.max = OPT_DOUBLE_C(1),
.precision = OPT_U32_C(309),
.expectError = "Precision is too large"}};

for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
DoubleTest *test = tests + i;
Expand Down Expand Up @@ -767,7 +781,18 @@ static void _test_RangeTest_Encode_Decimal128(_mongocrypt_tester_t *tester) {
#undef ASSERT_EIBB_OVERFLOW

/* Test cases copied from Decimal128_Bounds_Precision ... end */
};

{// Expect error due to precision exceeding INT32_MAX.
.min = OPT_MC_DEC128(MC_DEC128_C(1)),
.max = OPT_MC_DEC128(MC_DEC128_C(2)),
.precision = OPT_U32((uint32_t)INT32_MAX + 1),
.expectError = "Precision cannot be greater than 2147483647"},
{// Expect error due to precision exceeding max finite Decimal128.
// The largest decimal128 value is 9.99999...x10^6144. 10^6145 results in infinity.
.min = OPT_MC_DEC128(MC_DEC128_C(0)),
.max = OPT_MC_DEC128(MC_DEC128_C(1)),
.precision = OPT_U32(6145),
.expectError = "Precision is too large"}};

for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
Decimal128Test *test = tests + i;
Expand Down

0 comments on commit 6dff2a8

Please sign in to comment.