From 7d32b8e500abbf7ea3959f14d10d6ed7496269f4 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Thu, 27 Jan 2022 09:43:41 -0600 Subject: [PATCH 1/4] Add numeric limits compatibility support to bson-compat.h --- src/libbson/src/bson/bson-compat.h | 151 +++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/src/libbson/src/bson/bson-compat.h b/src/libbson/src/bson/bson-compat.h index d6556a28877..ef492925c1a 100644 --- a/src/libbson/src/bson/bson-compat.h +++ b/src/libbson/src/bson/bson-compat.h @@ -130,6 +130,157 @@ typedef SSIZE_T ssize_t; #endif #endif +/* Derive the maximum representable value of signed integer type T using the + * formula 2^(N - 1) - 1 where N is the number of bits in type T. This assumes + * T is represented using two's complement. */ +#define BSON_NUMERIC_LIMITS_MAX_SIGNED(T) \ + ((T) ((((size_t) 0x01u) << (sizeof (T) * (size_t) CHAR_BIT - 1u)) - 1u)) + +/* Derive the minimum representable value of signed integer type T as one less + * than the negation of its maximum representable value. This assumes T is + * represented using two's complement. */ +#define BSON_NUMERIC_LIMITS_MIN_SIGNED(T, max) ((T) ((-(max)) - 1)) + +/* Derive the maximum representable value of unsigned integer type T by flipping + * all its bits to 1. */ +#define BSON_NUMERIC_LIMITS_MAX_UNSIGNED(T) ((T) (~((T) 0))) + +/* Define numeric limit constants if not already available for C90 + * compatibility. These can be removed once C99 is declared the minimum + * supported C standard. */ +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L + +#ifndef SCHAR_MAX +#define SCHAR_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (signed char) +#endif + +#ifndef SHRT_MAX +#define SHRT_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (short) +#endif + +#ifndef INT_MAX +#define INT_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int) +#endif + +#ifndef LONG_MAX +#define LONG_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (long) +#endif + +#ifndef LLONG_MAX +#define LLONG_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (long long) +#endif + +#ifndef UCHAR_MAX +#define UCHAR_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned char) +#endif + +#ifndef USHRT_MAX +#define USHRT_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned short) +#endif + +#ifndef UINT_MAX +#define UINT_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned int) +#endif + +#ifndef ULONG_MAX +#define ULONG_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned long) +#endif + +#ifndef ULLONG_MAX +#define ULLONG_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned long long) +#endif + +#ifndef INT8_MAX +#define INT8_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int8_t) +#endif + +#ifndef INT16_MAX +#define INT16_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int16_t) +#endif + +#ifndef INT32_MAX +#define INT32_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int32_t) +#endif + +#ifndef INT64_MAX +#define INT64_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int64_t) +#endif + +#ifndef UINT8_MAX +#define UINT8_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint8_t) +#endif + +#ifndef UINT16_MAX +#define UINT16_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint16_t) +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint32_t) +#endif + +#ifndef UINT64_MAX +#define UINT64_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint64_t) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (size_t) +#endif + +#ifndef PTRDIFF_MAX +#define PTRDIFF_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (ptrdiff_t) +#endif + +#ifndef SCHAR_MIN +#define SCHAR_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (signed char, SCHAR_MAX) +#endif + +#ifndef SHRT_MIN +#define SHRT_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (short, SHRT_MAX) +#endif + +#ifndef INT_MIN +#define INT_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int, INT_MAX) +#endif + +#ifndef LONG_MIN +#define LONG_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (long, LONG_MAX) +#endif + +#ifndef LLONG_MIN +#define LLONG_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (long long, LLONG_MAX) +#endif + +#ifndef INT8_MIN +#define INT8_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int8_t, INT8_MAX) +#endif + +#ifndef INT16_MIN +#define INT16_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int16_t, INT16_MAX) +#endif + +#ifndef INT32_MIN +#define INT32_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int32_t, INT32_MAX) +#endif + +#ifndef INT64_MIN +#define INT64_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int64_t, INT64_MAX) +#endif + +#ifndef PTRDIFF_MIN +#define PTRDIFF_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (ptrdiff_t, PTRDIFF_MAX) +#endif + +#endif /* !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L */ + + +#ifndef SSIZE_MAX +#define SSIZE_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (ssize_t) +#endif + +#ifndef SSIZE_MIN +#define SSIZE_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (ssize_t, SSIZE_MAX) +#endif + #if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT) #define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT typedef RTL_RUN_ONCE INIT_ONCE; From 1c007a3bd54328a59b5ec08df58acdcb2cc5d762 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Wed, 26 Jan 2022 16:41:51 -0600 Subject: [PATCH 2/4] Add safe integral comparison functions --- src/libbson/CMakeLists.txt | 1 + src/libbson/src/bson/CMakeLists.txt | 1 + src/libbson/src/bson/bson-cmp.h | 196 +++++++++++++++++ src/libbson/src/bson/bson.h | 1 + src/libbson/tests/test-bson-cmp.c | 309 +++++++++++++++++++++++++++ src/libmongoc/CMakeLists.txt | 1 + src/libmongoc/tests/test-libmongoc.c | 3 + 7 files changed, 512 insertions(+) create mode 100644 src/libbson/src/bson/bson-cmp.h create mode 100644 src/libbson/tests/test-bson-cmp.c diff --git a/src/libbson/CMakeLists.txt b/src/libbson/CMakeLists.txt index 8c0f1d71cba..d6df66f8657 100644 --- a/src/libbson/CMakeLists.txt +++ b/src/libbson/CMakeLists.txt @@ -181,6 +181,7 @@ set (HEADERS ${PROJECT_SOURCE_DIR}/src/bson/bcon.h ${PROJECT_SOURCE_DIR}/src/bson/bson-atomic.h ${PROJECT_SOURCE_DIR}/src/bson/bson-clock.h + ${PROJECT_SOURCE_DIR}/src/bson/bson-cmp.h ${PROJECT_SOURCE_DIR}/src/bson/bson-compat.h ${PROJECT_SOURCE_DIR}/src/bson/bson-context.h ${PROJECT_SOURCE_DIR}/src/bson/bson-decimal128.h diff --git a/src/libbson/src/bson/CMakeLists.txt b/src/libbson/src/bson/CMakeLists.txt index 3f9ccf081a4..e7852d3ba2c 100644 --- a/src/libbson/src/bson/CMakeLists.txt +++ b/src/libbson/src/bson/CMakeLists.txt @@ -16,6 +16,7 @@ set (src_libbson_src_bson_DIST_hs bson-memory.h bson-oid.h bson-reader.h + bson-cmp.h bson-string.h bson-types.h bson-utf8.h diff --git a/src/libbson/src/bson/bson-cmp.h b/src/libbson/src/bson/bson-cmp.h new file mode 100644 index 00000000000..cfcfd5024ff --- /dev/null +++ b/src/libbson/src/bson/bson-cmp.h @@ -0,0 +1,196 @@ +/* + * Copyright 2022 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. + */ + +#include "bson-prelude.h" + + +#ifndef BSON_CMP_H +#define BSON_CMP_H + + +#include "bson-compat.h" /* ssize_t */ +#include "bson-macros.h" /* BSON_CONCAT */ + +#include +#include +#include + + +BSON_BEGIN_DECLS + + +/* 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.: + * - bson_cmp_less_ss (signed-value, signed-value) + * - bson_cmp_less_uu (unsigned-value, unsigned-value) + * - bson_cmp_less_su (signed-value, unsigned-value) + * - bson_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: + * - bson_in_range_signed (Type, signed-value) + * - bson_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 BSON_CMP_SET(op, ss, uu, su, us) \ + static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _ss) (int64_t t, \ + int64_t u) \ + { \ + return (ss); \ + } \ + \ + static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _uu) (uint64_t t, \ + uint64_t u) \ + { \ + return (uu); \ + } \ + \ + static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _su) (int64_t t, \ + uint64_t u) \ + { \ + return (su); \ + } \ + \ + static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _us) (uint64_t t, \ + int64_t u) \ + { \ + return (us); \ + } + +BSON_CMP_SET (equal, + t == u, + t == u, + t < 0 ? false : (uint64_t) (t) == u, + u < 0 ? false : t == (uint64_t) (u)) + +BSON_CMP_SET (not_equal, + !bson_cmp_equal_ss (t, u), + !bson_cmp_equal_uu (t, u), + !bson_cmp_equal_su (t, u), + !bson_cmp_equal_us (t, u)) + +BSON_CMP_SET (less, + t < u, + t < u, + t < 0 ? true : (uint64_t) (t) < u, + u < 0 ? false : t < (uint64_t) (u)) + +BSON_CMP_SET (greater, + bson_cmp_less_ss (u, t), + bson_cmp_less_uu (u, t), + bson_cmp_less_us (u, t), + bson_cmp_less_su (u, t)) + +BSON_CMP_SET (less_equal, + !bson_cmp_greater_ss (t, u), + !bson_cmp_greater_uu (t, u), + !bson_cmp_greater_su (t, u), + !bson_cmp_greater_us (t, u)) + +BSON_CMP_SET (greater_equal, + !bson_cmp_less_ss (t, u), + !bson_cmp_less_uu (t, u), + !bson_cmp_less_su (t, u), + !bson_cmp_less_us (t, u)) + +#undef BSON_CMP_SET + + +/* Define in_range functions for *signed* type Type. */ +#define BSON_IN_RANGE_SET_SIGNED(Type, min, max) \ + static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _signed) ( \ + int64_t value) \ + { \ + return bson_cmp_greater_equal_ss (value, min) && \ + bson_cmp_less_equal_ss (value, max); \ + } \ + \ + static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _unsigned) ( \ + uint64_t value) \ + { \ + return bson_cmp_greater_equal_us (value, min) && \ + bson_cmp_less_equal_us (value, max); \ + } + +/* Define in_range functions for *unsigned* type Type. */ +#define BSON_IN_RANGE_SET_UNSIGNED(Type, max) \ + static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _signed) ( \ + int64_t value) \ + { \ + return bson_cmp_greater_equal_su (value, 0u) && \ + bson_cmp_less_equal_su (value, max); \ + } \ + \ + static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _unsigned) ( \ + uint64_t value) \ + { \ + return bson_cmp_greater_equal_uu (value, 0u) && \ + bson_cmp_less_equal_uu (value, max); \ + } + +BSON_IN_RANGE_SET_SIGNED (signed_char, SCHAR_MIN, SCHAR_MAX) +BSON_IN_RANGE_SET_SIGNED (short, SHRT_MIN, SHRT_MAX) +BSON_IN_RANGE_SET_SIGNED (int, INT_MIN, INT_MAX) +BSON_IN_RANGE_SET_SIGNED (long, LONG_MIN, LONG_MAX) +BSON_IN_RANGE_SET_SIGNED (long_long, LLONG_MIN, LLONG_MAX) + +BSON_IN_RANGE_SET_UNSIGNED (unsigned_char, UCHAR_MAX) +BSON_IN_RANGE_SET_UNSIGNED (unsigned_short, USHRT_MAX) +BSON_IN_RANGE_SET_UNSIGNED (unsigned_int, UINT_MAX) +BSON_IN_RANGE_SET_UNSIGNED (unsigned_long, ULONG_MAX) +BSON_IN_RANGE_SET_UNSIGNED (unsigned_long_long, ULLONG_MAX) + +BSON_IN_RANGE_SET_SIGNED (int8_t, INT8_MIN, INT8_MAX) +BSON_IN_RANGE_SET_SIGNED (int16_t, INT16_MIN, INT16_MAX) +BSON_IN_RANGE_SET_SIGNED (int32_t, INT32_MIN, INT32_MAX) +BSON_IN_RANGE_SET_SIGNED (int64_t, INT64_MIN, INT64_MAX) + +BSON_IN_RANGE_SET_UNSIGNED (uint8_t, UINT8_MAX) +BSON_IN_RANGE_SET_UNSIGNED (uint16_t, UINT16_MAX) +BSON_IN_RANGE_SET_UNSIGNED (uint32_t, UINT32_MAX) +BSON_IN_RANGE_SET_UNSIGNED (uint64_t, UINT64_MAX) + +BSON_IN_RANGE_SET_SIGNED (ssize_t, SSIZE_MIN, SSIZE_MAX) +BSON_IN_RANGE_SET_UNSIGNED (size_t, SIZE_MAX) + +#undef BSON_IN_RANGE_SET_SIGNED +#undef BSON_IN_RANGE_SET_UNSIGNED + + +/* Return true if the value with *signed* type is in the representable range of + * Type and false otherwise. */ +#define bson_in_range_signed(Type, value) \ + BSON_CONCAT3 (bson_in_range_, Type, _signed) (value) + +/* Return true if the value with *unsigned* type is in the representable range + * of Type and false otherwise. */ +#define bson_in_range_unsigned(Type, value) \ + BSON_CONCAT3 (bson_in_range_, Type, _unsigned) (value) + + +BSON_END_DECLS + + +#endif /* BSON_CMP_H */ diff --git a/src/libbson/src/bson/bson.h b/src/libbson/src/bson/bson.h index 6a5006faa92..8ffc58ecbb4 100644 --- a/src/libbson/src/bson/bson.h +++ b/src/libbson/src/bson/bson.h @@ -28,6 +28,7 @@ #include "bson-macros.h" #include "bson-config.h" #include "bson-atomic.h" +#include "bson-cmp.h" #include "bson-context.h" #include "bson-clock.h" #include "bson-decimal128.h" diff --git a/src/libbson/tests/test-bson-cmp.c b/src/libbson/tests/test-bson-cmp.c new file mode 100644 index 00000000000..5d78f2cee28 --- /dev/null +++ b/src/libbson/tests/test-bson-cmp.c @@ -0,0 +1,309 @@ +/* + * Copyright 2022 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. + */ + +#include "TestSuite.h" + +#include + +static void +test_bson_cmp_equal (void) +{ + BSON_ASSERT (bson_cmp_equal_ss (0, 0)); + BSON_ASSERT (!bson_cmp_equal_ss (0, -1)); + BSON_ASSERT (!bson_cmp_equal_ss (0, 1)); + BSON_ASSERT (!bson_cmp_equal_ss (-1, 0)); + BSON_ASSERT (bson_cmp_equal_ss (-1, -1)); + BSON_ASSERT (!bson_cmp_equal_ss (-1, 1)); + BSON_ASSERT (!bson_cmp_equal_ss (1, 0)); + BSON_ASSERT (!bson_cmp_equal_ss (1, -1)); + BSON_ASSERT (bson_cmp_equal_ss (1, 1)); + + BSON_ASSERT (bson_cmp_equal_uu (0u, 0u)); + BSON_ASSERT (!bson_cmp_equal_uu (0u, 1u)); + BSON_ASSERT (!bson_cmp_equal_uu (1u, 0u)); + BSON_ASSERT (bson_cmp_equal_uu (1u, 1u)); + + BSON_ASSERT (bson_cmp_equal_su (0, 0u)); + BSON_ASSERT (!bson_cmp_equal_su (0, 1u)); + BSON_ASSERT (!bson_cmp_equal_su (-1, 0u)); + BSON_ASSERT (!bson_cmp_equal_su (-1, 1u)); + BSON_ASSERT (!bson_cmp_equal_su (1, 0u)); + BSON_ASSERT (bson_cmp_equal_su (1, 1u)); + + BSON_ASSERT (bson_cmp_equal_us (0u, 0)); + BSON_ASSERT (!bson_cmp_equal_us (0u, -1)); + BSON_ASSERT (!bson_cmp_equal_us (0u, 1)); + BSON_ASSERT (!bson_cmp_equal_us (1u, 0)); + BSON_ASSERT (!bson_cmp_equal_us (1u, -1)); + BSON_ASSERT (bson_cmp_equal_us (1u, 1)); +} + +static void +test_bson_cmp_not_equal (void) +{ + BSON_ASSERT (!bson_cmp_not_equal_ss (0, 0)); + BSON_ASSERT (bson_cmp_not_equal_ss (0, -1)); + BSON_ASSERT (bson_cmp_not_equal_ss (0, 1)); + BSON_ASSERT (bson_cmp_not_equal_ss (-1, 0)); + BSON_ASSERT (!bson_cmp_not_equal_ss (-1, -1)); + BSON_ASSERT (bson_cmp_not_equal_ss (-1, 1)); + BSON_ASSERT (bson_cmp_not_equal_ss (1, 0)); + BSON_ASSERT (bson_cmp_not_equal_ss (1, -1)); + BSON_ASSERT (!bson_cmp_not_equal_ss (1, 1)); + + BSON_ASSERT (!bson_cmp_not_equal_uu (0u, 0u)); + BSON_ASSERT (bson_cmp_not_equal_uu (0u, 1u)); + BSON_ASSERT (bson_cmp_not_equal_uu (1u, 0u)); + BSON_ASSERT (!bson_cmp_not_equal_uu (1u, 1u)); + + BSON_ASSERT (!bson_cmp_not_equal_su (0, 0u)); + BSON_ASSERT (bson_cmp_not_equal_su (0, 1u)); + BSON_ASSERT (bson_cmp_not_equal_su (-1, 0u)); + BSON_ASSERT (bson_cmp_not_equal_su (-1, 1u)); + BSON_ASSERT (bson_cmp_not_equal_su (1, 0u)); + BSON_ASSERT (!bson_cmp_not_equal_su (1, 1u)); + + BSON_ASSERT (!bson_cmp_not_equal_us (0u, 0)); + BSON_ASSERT (bson_cmp_not_equal_us (0u, -1)); + BSON_ASSERT (bson_cmp_not_equal_us (0u, 1)); + BSON_ASSERT (bson_cmp_not_equal_us (1u, 0)); + BSON_ASSERT (bson_cmp_not_equal_us (1u, -1)); + BSON_ASSERT (!bson_cmp_not_equal_us (1u, 1)); +} + +static void +test_bson_cmp_less (void) +{ + BSON_ASSERT (!bson_cmp_less_ss (0, 0)); + BSON_ASSERT (!bson_cmp_less_ss (0, -1)); + BSON_ASSERT (bson_cmp_less_ss (0, 1)); + BSON_ASSERT (bson_cmp_less_ss (-1, 0)); + BSON_ASSERT (!bson_cmp_less_ss (-1, -1)); + BSON_ASSERT (bson_cmp_less_ss (-1, 1)); + BSON_ASSERT (!bson_cmp_less_ss (1, 0)); + BSON_ASSERT (!bson_cmp_less_ss (1, -1)); + BSON_ASSERT (!bson_cmp_less_ss (1, 1)); + + BSON_ASSERT (!bson_cmp_less_uu (0u, 0)); + BSON_ASSERT (bson_cmp_less_uu (0u, 1u)); + BSON_ASSERT (!bson_cmp_less_uu (1u, 0u)); + BSON_ASSERT (!bson_cmp_less_uu (1u, 1u)); + + BSON_ASSERT (!bson_cmp_less_su (0, 0u)); + BSON_ASSERT (bson_cmp_less_su (0, 1u)); + BSON_ASSERT (bson_cmp_less_su (-1, 0u)); + BSON_ASSERT (bson_cmp_less_su (-1, 1u)); + BSON_ASSERT (!bson_cmp_less_su (1, 0u)); + BSON_ASSERT (!bson_cmp_less_su (1, 1u)); + + BSON_ASSERT (!bson_cmp_less_us (0u, 0)); + BSON_ASSERT (!bson_cmp_less_us (0u, -1)); + BSON_ASSERT (bson_cmp_less_us (0u, 1)); + BSON_ASSERT (!bson_cmp_less_us (1u, 0)); + BSON_ASSERT (!bson_cmp_less_us (1u, -1)); + BSON_ASSERT (!bson_cmp_less_us (1u, 1)); +} + +static void +test_bson_cmp_greater (void) +{ + BSON_ASSERT (!bson_cmp_greater_ss (0, 0)); + BSON_ASSERT (bson_cmp_greater_ss (0, -1)); + BSON_ASSERT (!bson_cmp_greater_ss (0, 1)); + BSON_ASSERT (!bson_cmp_greater_ss (-1, 0)); + BSON_ASSERT (!bson_cmp_greater_ss (-1, -1)); + BSON_ASSERT (!bson_cmp_greater_ss (-1, 1)); + BSON_ASSERT (bson_cmp_greater_ss (1, 0)); + BSON_ASSERT (bson_cmp_greater_ss (1, -1)); + BSON_ASSERT (!bson_cmp_greater_ss (1, 1)); + + BSON_ASSERT (!bson_cmp_greater_uu (0u, 0)); + BSON_ASSERT (!bson_cmp_greater_uu (0u, 1u)); + BSON_ASSERT (bson_cmp_greater_uu (1u, 0u)); + BSON_ASSERT (!bson_cmp_greater_uu (1u, 1u)); + + BSON_ASSERT (!bson_cmp_greater_su (0, 0u)); + BSON_ASSERT (!bson_cmp_greater_su (0, 1u)); + BSON_ASSERT (!bson_cmp_greater_su (-1, 0u)); + BSON_ASSERT (!bson_cmp_greater_su (-1, 1u)); + BSON_ASSERT (bson_cmp_greater_su (1, 0u)); + BSON_ASSERT (!bson_cmp_greater_su (1, 1u)); + + BSON_ASSERT (!bson_cmp_greater_us (0u, 0)); + BSON_ASSERT (bson_cmp_greater_us (0u, -1)); + BSON_ASSERT (!bson_cmp_greater_us (0u, 1)); + BSON_ASSERT (bson_cmp_greater_us (1u, 0)); + BSON_ASSERT (bson_cmp_greater_us (1u, -1)); + BSON_ASSERT (!bson_cmp_greater_us (1u, 1)); +} + +static void +test_bson_cmp_less_equal (void) +{ + BSON_ASSERT (bson_cmp_less_equal_ss (0, 0)); + BSON_ASSERT (!bson_cmp_less_equal_ss (0, -1)); + BSON_ASSERT (bson_cmp_less_equal_ss (0, 1)); + BSON_ASSERT (bson_cmp_less_equal_ss (-1, 0)); + BSON_ASSERT (bson_cmp_less_equal_ss (-1, -1)); + BSON_ASSERT (bson_cmp_less_equal_ss (-1, 1)); + BSON_ASSERT (!bson_cmp_less_equal_ss (1, 0)); + BSON_ASSERT (!bson_cmp_less_equal_ss (1, -1)); + BSON_ASSERT (bson_cmp_less_equal_ss (1, 1)); + + BSON_ASSERT (bson_cmp_less_equal_uu (0u, 0)); + BSON_ASSERT (bson_cmp_less_equal_uu (0u, 1u)); + BSON_ASSERT (!bson_cmp_less_equal_uu (1u, 0u)); + BSON_ASSERT (bson_cmp_less_equal_uu (1u, 1u)); + + BSON_ASSERT (bson_cmp_less_equal_su (0, 0u)); + BSON_ASSERT (bson_cmp_less_equal_su (0, 1u)); + BSON_ASSERT (bson_cmp_less_equal_su (-1, 0u)); + BSON_ASSERT (bson_cmp_less_equal_su (-1, 1u)); + BSON_ASSERT (!bson_cmp_less_equal_su (1, 0u)); + BSON_ASSERT (bson_cmp_less_equal_su (1, 1u)); + + BSON_ASSERT (bson_cmp_less_equal_us (0u, 0)); + BSON_ASSERT (!bson_cmp_less_equal_us (0u, -1)); + BSON_ASSERT (bson_cmp_less_equal_us (0u, 1)); + BSON_ASSERT (!bson_cmp_less_equal_us (1u, 0)); + BSON_ASSERT (!bson_cmp_less_equal_us (1u, -1)); + BSON_ASSERT (bson_cmp_less_equal_us (1u, 1)); +} + +static void +test_bson_cmp_greater_equal (void) +{ + BSON_ASSERT (bson_cmp_greater_equal_ss (0, 0)); + BSON_ASSERT (bson_cmp_greater_equal_ss (0, -1)); + BSON_ASSERT (!bson_cmp_greater_equal_ss (0, 1)); + BSON_ASSERT (!bson_cmp_greater_equal_ss (-1, 0)); + BSON_ASSERT (bson_cmp_greater_equal_ss (-1, -1)); + BSON_ASSERT (!bson_cmp_greater_equal_ss (-1, 1)); + BSON_ASSERT (bson_cmp_greater_equal_ss (1, 0)); + BSON_ASSERT (bson_cmp_greater_equal_ss (1, -1)); + BSON_ASSERT (bson_cmp_greater_equal_ss (1, 1)); + + BSON_ASSERT (bson_cmp_greater_equal_uu (0u, 0)); + BSON_ASSERT (!bson_cmp_greater_equal_uu (0u, 1u)); + BSON_ASSERT (bson_cmp_greater_equal_uu (1u, 0u)); + BSON_ASSERT (bson_cmp_greater_equal_uu (1u, 1u)); + + BSON_ASSERT (bson_cmp_greater_equal_su (0, 0u)); + BSON_ASSERT (!bson_cmp_greater_equal_su (0, 1u)); + BSON_ASSERT (!bson_cmp_greater_equal_su (-1, 0u)); + BSON_ASSERT (!bson_cmp_greater_equal_su (-1, 1u)); + BSON_ASSERT (bson_cmp_greater_equal_su (1, 0u)); + BSON_ASSERT (bson_cmp_greater_equal_su (1, 1u)); + + BSON_ASSERT (bson_cmp_greater_equal_us (0u, 0)); + BSON_ASSERT (bson_cmp_greater_equal_us (0u, -1)); + BSON_ASSERT (!bson_cmp_greater_equal_us (0u, 1)); + BSON_ASSERT (bson_cmp_greater_equal_us (1u, 0)); + BSON_ASSERT (bson_cmp_greater_equal_us (1u, -1)); + BSON_ASSERT (bson_cmp_greater_equal_us (1u, 1)); +} + +/* 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); + +static void +test_bson_in_range (void) +{ + const int64_t int8_min = INT8_MIN; + const int64_t int8_max = INT8_MAX; + const int64_t int32_min = INT32_MIN; + const int64_t int32_max = INT32_MAX; + + const uint64_t uint8_max = UINT8_MAX; + const uint64_t uint32_max = UINT32_MAX; + + const ssize_t ssize_min = SSIZE_MIN; + const ssize_t ssize_max = SSIZE_MAX; + + BSON_ASSERT (!bson_in_range_signed (int8_t, int8_min - 1)); + BSON_ASSERT (bson_in_range_signed (int8_t, int8_min)); + BSON_ASSERT (bson_in_range_signed (int8_t, 0)); + BSON_ASSERT (bson_in_range_signed (int8_t, int8_max)); + BSON_ASSERT (!bson_in_range_signed (int8_t, int8_max + 1)); + + BSON_ASSERT (bson_in_range_unsigned (int8_t, 0u)); + BSON_ASSERT (bson_in_range_unsigned (int8_t, (uint64_t) int8_max)); + BSON_ASSERT (!bson_in_range_unsigned (int8_t, (uint64_t) (int8_max + 1))); + + BSON_ASSERT (!bson_in_range_signed (uint8_t, int8_min - 1)); + BSON_ASSERT (!bson_in_range_signed (uint8_t, int8_min)); + BSON_ASSERT (bson_in_range_signed (uint8_t, 0)); + BSON_ASSERT (bson_in_range_signed (uint8_t, int8_max)); + BSON_ASSERT (bson_in_range_signed (uint8_t, int8_max + 1)); + BSON_ASSERT (bson_in_range_signed (uint8_t, (int64_t) uint8_max)); + BSON_ASSERT (!bson_in_range_signed (uint8_t, (int64_t) uint8_max + 1)); + + BSON_ASSERT (bson_in_range_unsigned (uint8_t, 0u)); + BSON_ASSERT (bson_in_range_unsigned (uint8_t, uint8_max)); + BSON_ASSERT (!bson_in_range_unsigned (uint8_t, uint8_max + 1u)); + + BSON_ASSERT (!bson_in_range_signed (int32_t, int32_min - 1)); + BSON_ASSERT (bson_in_range_signed (int32_t, int32_min)); + BSON_ASSERT (bson_in_range_signed (int32_t, 0)); + BSON_ASSERT (bson_in_range_signed (int32_t, int32_max)); + BSON_ASSERT (!bson_in_range_signed (int32_t, int32_max + 1)); + + BSON_ASSERT (bson_in_range_unsigned (int32_t, 0u)); + BSON_ASSERT (bson_in_range_unsigned (int32_t, (uint64_t) int32_max)); + BSON_ASSERT (!bson_in_range_unsigned (int32_t, (uint64_t) (int32_max + 1))); + + BSON_ASSERT (!bson_in_range_signed (uint32_t, int32_min - 1)); + BSON_ASSERT (!bson_in_range_signed (uint32_t, int32_min)); + BSON_ASSERT (bson_in_range_signed (uint32_t, 0)); + BSON_ASSERT (bson_in_range_signed (uint32_t, int32_max)); + BSON_ASSERT (bson_in_range_signed (uint32_t, int32_max + 1)); + BSON_ASSERT (bson_in_range_signed (uint32_t, (int64_t) uint32_max)); + BSON_ASSERT (!bson_in_range_signed (uint32_t, (int64_t) uint32_max + 1)); + + BSON_ASSERT (bson_in_range_unsigned (uint32_t, 0u)); + BSON_ASSERT (bson_in_range_unsigned (uint32_t, uint32_max)); + BSON_ASSERT (!bson_in_range_unsigned (uint32_t, uint32_max + 1u)); + + BSON_ASSERT (bson_in_range_signed (ssize_t, ssize_min)); + BSON_ASSERT (bson_in_range_signed (ssize_t, 0)); + BSON_ASSERT (bson_in_range_signed (ssize_t, ssize_max)); + + BSON_ASSERT (bson_in_range_unsigned (ssize_t, 0u)); + BSON_ASSERT (bson_in_range_unsigned (ssize_t, (size_t) ssize_max)); + BSON_ASSERT (!bson_in_range_unsigned (ssize_t, (size_t) ssize_max + 1u)); + + BSON_ASSERT (!bson_in_range_signed (size_t, ssize_min)); + BSON_ASSERT (bson_in_range_signed (size_t, 0)); + BSON_ASSERT (bson_in_range_signed (size_t, ssize_max)); + + BSON_ASSERT (bson_in_range_unsigned (size_t, 0u)); + BSON_ASSERT (bson_in_range_unsigned (size_t, (size_t) ssize_max)); + BSON_ASSERT (bson_in_range_unsigned (size_t, (size_t) ssize_max + 1u)); +} + +void +test_bson_cmp_install (TestSuite *suite) +{ + TestSuite_Add (suite, "/bson/cmp/equal", test_bson_cmp_equal); + TestSuite_Add (suite, "/bson/cmp/not_equal", test_bson_cmp_not_equal); + TestSuite_Add (suite, "/bson/cmp/less", test_bson_cmp_less); + TestSuite_Add (suite, "/bson/cmp/greater", test_bson_cmp_greater); + TestSuite_Add (suite, "/bson/cmp/less_equal", test_bson_cmp_less_equal); + TestSuite_Add ( + suite, "/bson/cmp/greater_equal", test_bson_cmp_greater_equal); + TestSuite_Add (suite, "/bson/cmp/in_range", test_bson_in_range); +} diff --git a/src/libmongoc/CMakeLists.txt b/src/libmongoc/CMakeLists.txt index cf8eb311904..84781097a9c 100644 --- a/src/libmongoc/CMakeLists.txt +++ b/src/libmongoc/CMakeLists.txt @@ -911,6 +911,7 @@ set (test-libmongoc-sources ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bson.c ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bcon-basic.c ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bcon-extract.c + ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bson-cmp.c ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bson-corpus.c ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bson-error.c ${PROJECT_SOURCE_DIR}/../../src/libbson/tests/test-bson-version.c diff --git a/src/libmongoc/tests/test-libmongoc.c b/src/libmongoc/tests/test-libmongoc.c index fd9459111c6..dfcc1d59b44 100644 --- a/src/libmongoc/tests/test-libmongoc.c +++ b/src/libmongoc/tests/test-libmongoc.c @@ -86,6 +86,8 @@ extern void test_writer_install (TestSuite *suite); extern void test_b64_install (TestSuite *suite); +extern void +test_bson_cmp_install (TestSuite *suite); /* libmongoc */ @@ -2939,6 +2941,7 @@ main (int argc, char *argv[]) test_value_install (&suite); test_writer_install (&suite); test_b64_install (&suite); + test_bson_cmp_install (&suite); /* libmongoc */ From 6740d14afed3257dbae69ee65689657164eedf59 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Fri, 25 Mar 2022 10:46:06 -0500 Subject: [PATCH 3/4] Update literals with consistent unsigned-suffixes --- src/libbson/tests/test-bson-cmp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libbson/tests/test-bson-cmp.c b/src/libbson/tests/test-bson-cmp.c index 5d78f2cee28..fd922305d33 100644 --- a/src/libbson/tests/test-bson-cmp.c +++ b/src/libbson/tests/test-bson-cmp.c @@ -97,7 +97,7 @@ test_bson_cmp_less (void) BSON_ASSERT (!bson_cmp_less_ss (1, -1)); BSON_ASSERT (!bson_cmp_less_ss (1, 1)); - BSON_ASSERT (!bson_cmp_less_uu (0u, 0)); + BSON_ASSERT (!bson_cmp_less_uu (0u, 0u)); BSON_ASSERT (bson_cmp_less_uu (0u, 1u)); BSON_ASSERT (!bson_cmp_less_uu (1u, 0u)); BSON_ASSERT (!bson_cmp_less_uu (1u, 1u)); @@ -130,7 +130,7 @@ test_bson_cmp_greater (void) BSON_ASSERT (bson_cmp_greater_ss (1, -1)); BSON_ASSERT (!bson_cmp_greater_ss (1, 1)); - BSON_ASSERT (!bson_cmp_greater_uu (0u, 0)); + BSON_ASSERT (!bson_cmp_greater_uu (0u, 0u)); BSON_ASSERT (!bson_cmp_greater_uu (0u, 1u)); BSON_ASSERT (bson_cmp_greater_uu (1u, 0u)); BSON_ASSERT (!bson_cmp_greater_uu (1u, 1u)); @@ -163,7 +163,7 @@ test_bson_cmp_less_equal (void) BSON_ASSERT (!bson_cmp_less_equal_ss (1, -1)); BSON_ASSERT (bson_cmp_less_equal_ss (1, 1)); - BSON_ASSERT (bson_cmp_less_equal_uu (0u, 0)); + BSON_ASSERT (bson_cmp_less_equal_uu (0u, 0u)); BSON_ASSERT (bson_cmp_less_equal_uu (0u, 1u)); BSON_ASSERT (!bson_cmp_less_equal_uu (1u, 0u)); BSON_ASSERT (bson_cmp_less_equal_uu (1u, 1u)); @@ -196,7 +196,7 @@ test_bson_cmp_greater_equal (void) BSON_ASSERT (bson_cmp_greater_equal_ss (1, -1)); BSON_ASSERT (bson_cmp_greater_equal_ss (1, 1)); - BSON_ASSERT (bson_cmp_greater_equal_uu (0u, 0)); + BSON_ASSERT (bson_cmp_greater_equal_uu (0u, 0u)); BSON_ASSERT (!bson_cmp_greater_equal_uu (0u, 1u)); BSON_ASSERT (bson_cmp_greater_equal_uu (1u, 0u)); BSON_ASSERT (bson_cmp_greater_equal_uu (1u, 1u)); From 7a7ae240dd4c78267dc02ed71f4cb3f85663e7a7 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Thu, 7 Apr 2022 12:26:40 -0500 Subject: [PATCH 4/4] Remove redundant comparison for unsigned-unsigned range check --- src/libbson/src/bson/bson-cmp.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libbson/src/bson/bson-cmp.h b/src/libbson/src/bson/bson-cmp.h index cfcfd5024ff..f9196d32dc5 100644 --- a/src/libbson/src/bson/bson-cmp.h +++ b/src/libbson/src/bson/bson-cmp.h @@ -146,8 +146,7 @@ BSON_CMP_SET (greater_equal, static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _unsigned) ( \ uint64_t value) \ { \ - return bson_cmp_greater_equal_uu (value, 0u) && \ - bson_cmp_less_equal_uu (value, max); \ + return bson_cmp_less_equal_uu (value, max); \ } BSON_IN_RANGE_SET_SIGNED (signed_char, SCHAR_MIN, SCHAR_MAX)