Skip to content

Commit

Permalink
MONGOCRYPT-724 remove use of bson-cmp.h (#890)
Browse files Browse the repository at this point in the history
* copy `bson-cmp.h` to `mc-cmp-private.h`

* replace `bson_cmp` and `bson_in_range` with `mc_cmp` and `mc_in_range`
  • Loading branch information
kevinAlbs authored Oct 7, 2024
1 parent a650d17 commit 8943552
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 6 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ endif ()

set (TEST_MONGOCRYPT_SOURCES
test/test-gcp-auth.c
test/test-mc-cmp.c
test/test-mc-efc.c
test/test-mc-fle2-find-equality-payload-v2.c
test/test-mc-fle2-find-range-payload-v2.c
Expand Down
137 changes: 137 additions & 0 deletions src/mc-cmp-private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright 2018-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// `cmp.h` is a modified copy of `bson-cmp.h` from libbson 1.28.0.
#ifndef MC_CMP_H
#define MC_CMP_H

#include <bson/bson.h> /* ssize_t + BSON_CONCAT */

#include <limits.h>
#include <stdbool.h>
#include <stdint.h>

/* Sanity check: ensure ssize_t limits are as expected relative to size_t. */
BSON_STATIC_ASSERT2(ssize_t_size_min_check, SSIZE_MIN + 1 == -SSIZE_MAX);
BSON_STATIC_ASSERT2(ssize_t_size_max_check, (size_t)SSIZE_MAX <= SIZE_MAX);

/* Based on the "Safe Integral Comparisons" proposal merged in C++20:
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0586r2.html
*
* Due to lack of type deduction in C, relational comparison functions (e.g.
* `cmp_less`) are defined in sets of four "functions" according to the
* signedness of each value argument, e.g.:
* - mc_cmp_less_ss (signed-value, signed-value)
* - mc_cmp_less_uu (unsigned-value, unsigned-value)
* - mc_cmp_less_su (signed-value, unsigned-value)
* - mc_cmp_less_us (unsigned-value, signed-value)
*
* Similarly, the `in_range` function is defined as a set of two "functions"
* according to the signedness of the value argument:
* - mc_in_range_signed (Type, signed-value)
* - mc_in_range_unsigned (Type, unsigned-value)
*
* The user must take care to use the correct signedness for the provided
* argument(s). Enabling compiler warnings for implicit sign conversions is
* recommended.
*/

#define MC_CMP_SET(op, ss, uu, su, us) \
static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _ss)(int64_t t, int64_t u) { return (ss); } \
\
static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _uu)(uint64_t t, uint64_t u) { return (uu); } \
\
static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _su)(int64_t t, uint64_t u) { return (su); } \
\
static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _us)(uint64_t t, int64_t u) { return (us); }

MC_CMP_SET(equal, t == u, t == u, t < 0 ? false : (uint64_t)(t) == u, u < 0 ? false : t == (uint64_t)(u))

MC_CMP_SET(not_equal, !mc_cmp_equal_ss(t, u), !mc_cmp_equal_uu(t, u), !mc_cmp_equal_su(t, u), !mc_cmp_equal_us(t, u))

MC_CMP_SET(less, t < u, t < u, t < 0 ? true : (uint64_t)(t) < u, u < 0 ? false : t < (uint64_t)(u))

MC_CMP_SET(greater, mc_cmp_less_ss(u, t), mc_cmp_less_uu(u, t), mc_cmp_less_us(u, t), mc_cmp_less_su(u, t))

MC_CMP_SET(less_equal,
!mc_cmp_greater_ss(t, u),
!mc_cmp_greater_uu(t, u),
!mc_cmp_greater_su(t, u),
!mc_cmp_greater_us(t, u))

MC_CMP_SET(greater_equal, !mc_cmp_less_ss(t, u), !mc_cmp_less_uu(t, u), !mc_cmp_less_su(t, u), !mc_cmp_less_us(t, u))

#undef MC_CMP_SET

/* Return true if the given value is within the range of the corresponding
* signed type. The suffix must match the signedness of the given value. */
#define MC_IN_RANGE_SET_SIGNED(Type, min, max) \
static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _signed)(int64_t value) { \
return mc_cmp_greater_equal_ss(value, min) && mc_cmp_less_equal_ss(value, max); \
} \
\
static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _unsigned)(uint64_t value) { \
return mc_cmp_greater_equal_us(value, min) && mc_cmp_less_equal_us(value, max); \
}

/* Return true if the given value is within the range of the corresponding
* unsigned type. The suffix must match the signedness of the given value. */
#define MC_IN_RANGE_SET_UNSIGNED(Type, max) \
static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _signed)(int64_t value) { \
return mc_cmp_greater_equal_su(value, 0u) && mc_cmp_less_equal_su(value, max); \
} \
\
static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _unsigned)(uint64_t value) { \
return mc_cmp_less_equal_uu(value, max); \
}

MC_IN_RANGE_SET_SIGNED(signed_char, SCHAR_MIN, SCHAR_MAX)
MC_IN_RANGE_SET_SIGNED(short, SHRT_MIN, SHRT_MAX)
MC_IN_RANGE_SET_SIGNED(int, INT_MIN, INT_MAX)
MC_IN_RANGE_SET_SIGNED(long, LONG_MIN, LONG_MAX)
MC_IN_RANGE_SET_SIGNED(long_long, LLONG_MIN, LLONG_MAX)

MC_IN_RANGE_SET_UNSIGNED(unsigned_char, UCHAR_MAX)
MC_IN_RANGE_SET_UNSIGNED(unsigned_short, USHRT_MAX)
MC_IN_RANGE_SET_UNSIGNED(unsigned_int, UINT_MAX)
MC_IN_RANGE_SET_UNSIGNED(unsigned_long, ULONG_MAX)
MC_IN_RANGE_SET_UNSIGNED(unsigned_long_long, ULLONG_MAX)

MC_IN_RANGE_SET_SIGNED(int8_t, INT8_MIN, INT8_MAX)
MC_IN_RANGE_SET_SIGNED(int16_t, INT16_MIN, INT16_MAX)
MC_IN_RANGE_SET_SIGNED(int32_t, INT32_MIN, INT32_MAX)
MC_IN_RANGE_SET_SIGNED(int64_t, INT64_MIN, INT64_MAX)

MC_IN_RANGE_SET_UNSIGNED(uint8_t, UINT8_MAX)
MC_IN_RANGE_SET_UNSIGNED(uint16_t, UINT16_MAX)
MC_IN_RANGE_SET_UNSIGNED(uint32_t, UINT32_MAX)
MC_IN_RANGE_SET_UNSIGNED(uint64_t, UINT64_MAX)

MC_IN_RANGE_SET_SIGNED(ssize_t, SSIZE_MIN, SSIZE_MAX)
MC_IN_RANGE_SET_UNSIGNED(size_t, SIZE_MAX)

#undef MC_IN_RANGE_SET_SIGNED
#undef MC_IN_RANGE_SET_UNSIGNED

/* Return true if the value with *signed* type is in the representable range of
* Type and false otherwise. */
#define mc_in_range_signed(Type, value) BSON_CONCAT3(mc_in_range, _##Type, _signed)(value)

/* Return true if the value with *unsigned* type is in the representable range
* of Type and false otherwise. */
#define mc_in_range_unsigned(Type, value) BSON_CONCAT3(mc_in_range, _##Type, _unsigned)(value)

#endif /* MC_CMP_H */
5 changes: 3 additions & 2 deletions src/mc-range-edge-generation.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "mc-array-private.h"
#include "mc-check-conversions-private.h"
#include "mc-cmp-private.h"
#include "mc-range-encoding-private.h"
#include "mongocrypt-private.h"

Expand Down Expand Up @@ -47,7 +48,7 @@ static mc_edges_t *mc_edges_new(const char *leaf,

const size_t leaf_len = strlen(leaf);
const int32_t trimFactor = trimFactorDefault(leaf_len, opt_trimFactor, use_range_v2);
if (trimFactor != 0 && bson_cmp_greater_equal_su(trimFactor, leaf_len)) {
if (trimFactor != 0 && mc_cmp_greater_equal_su(trimFactor, leaf_len)) {
// We append a total of leaf_len + 1 (for the root) - trimFactor edges. When this number is equal to 1, we
// degenerate into equality, which is not desired, so trimFactor must be less than leaf_len.
CLIENT_ERR("trimFactor must be less than the number of bits (%ld) used to represent an element of the domain, "
Expand Down Expand Up @@ -76,7 +77,7 @@ static mc_edges_t *mc_edges_new(const char *leaf,
_mc_array_append_val(&edges->edges, leaf_copy);

// Start loop at max(trimFactor, 1). The full leaf is unconditionally appended after loop.
BSON_ASSERT(bson_in_range_size_t_signed(trimFactor));
BSON_ASSERT(mc_in_range_size_t_signed(trimFactor));
size_t trimFactor_sz = (size_t)trimFactor;
size_t startLevel = trimFactor > 0 ? trimFactor_sz : 1;
for (size_t i = startLevel; i < leaf_len; i++) {
Expand Down
3 changes: 2 additions & 1 deletion src/mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "mc-check-conversions-private.h"
#include "mc-cmp-private.h"
#include "mc-range-encoding-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-util-private.h" // mc_isinf
Expand Down Expand Up @@ -863,7 +864,7 @@ int32_t trimFactorDefault(size_t maxlen, mc_optional_int32_t trimFactor, bool us
return 0;
}

if (bson_cmp_greater_su(mc_FLERangeTrimFactorDefault, maxlen - 1)) {
if (mc_cmp_greater_su(mc_FLERangeTrimFactorDefault, maxlen - 1)) {
return (int32_t)(maxlen - 1);
} else {
return mc_FLERangeTrimFactorDefault;
Expand Down
4 changes: 2 additions & 2 deletions src/mc-range-mincover-generator.template.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ static inline DECORATE_NAME(MinCoverGenerator)
}
size_t maxlen = (size_t)BITS - DECORATE_NAME(mc_count_leading_zeros)(max);
int32_t trimFactor = trimFactorDefault(maxlen, opt_trimFactor, use_range_v2);
if (trimFactor != 0 && bson_cmp_greater_equal_su(trimFactor, maxlen)) {
if (trimFactor != 0 && mc_cmp_greater_equal_su(trimFactor, maxlen)) {
CLIENT_ERR("Trim factor must be less than the number of bits (%ld) used to represent an element of the domain, "
"but got %" PRId32,
maxlen,
Expand Down Expand Up @@ -169,7 +169,7 @@ static inline bool DECORATE_NAME(MinCoverGenerator_isLevelStored)(DECORATE_NAME(
size_t maskedBits) {
BSON_ASSERT_PARAM(mcg);
size_t level = mcg->_maxlen - maskedBits;
BSON_ASSERT(bson_in_range_size_t_signed(mcg->_trimFactor));
BSON_ASSERT(mc_in_range_size_t_signed(mcg->_trimFactor));
size_t trimFactor_sz = (size_t)mcg->_trimFactor;
return 0 == maskedBits || (level >= trimFactor_sz && 0 == (level % mcg->_sparsity));
}
Expand Down
1 change: 1 addition & 0 deletions src/mc-range-mincover.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "mc-check-conversions-private.h"

#include "mc-array-private.h"
#include "mc-cmp-private.h"
#include "mc-range-edge-generation-private.h" // mc_count_leading_zeros_u32
#include "mc-range-encoding-private.h" // mc_getTypeInfo32, trimFactorDefault
#include "mc-range-mincover-private.h"
Expand Down
3 changes: 2 additions & 1 deletion src/mc-rangeopts.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "mc-rangeopts-private.h"

#include "mc-check-conversions-private.h"
#include "mc-cmp-private.h"
#include "mc-range-edge-generation-private.h" // mc_count_leading_zeros_XX
#include "mc-range-encoding-private.h" // mc_getTypeInfoXX
#include "mongocrypt-private.h"
Expand Down Expand Up @@ -504,7 +505,7 @@ bool mc_RangeOpts_appendTrimFactor(const mc_RangeOpts_t *ro,
}
// if nbits = 0, we want to allow trim factor = 0.
uint32_t test = nbits ? nbits : 1;
if (bson_cmp_greater_equal_su(ro->trimFactor.value, test)) {
if (mc_cmp_greater_equal_su(ro->trimFactor.value, test)) {
CLIENT_ERR_PREFIXED("Trim factor (%d) must be less than the total number of bits (%d) used to represent "
"any element in the domain.",
ro->trimFactor.value,
Expand Down
Loading

0 comments on commit 8943552

Please sign in to comment.