Skip to content

Commit 3032eeb

Browse files
authored
Reducing Warnings - Safe Integral Comparisons (#960)
* Add numeric limits compatibility support to bson-compat.h * Add safe integral comparison functions
1 parent 18b212a commit 3032eeb

File tree

8 files changed

+662
-0
lines changed

8 files changed

+662
-0
lines changed

src/libbson/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ set (HEADERS
181181
${PROJECT_SOURCE_DIR}/src/bson/bcon.h
182182
${PROJECT_SOURCE_DIR}/src/bson/bson-atomic.h
183183
${PROJECT_SOURCE_DIR}/src/bson/bson-clock.h
184+
${PROJECT_SOURCE_DIR}/src/bson/bson-cmp.h
184185
${PROJECT_SOURCE_DIR}/src/bson/bson-compat.h
185186
${PROJECT_SOURCE_DIR}/src/bson/bson-context.h
186187
${PROJECT_SOURCE_DIR}/src/bson/bson-decimal128.h

src/libbson/src/bson/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ set (src_libbson_src_bson_DIST_hs
1616
bson-memory.h
1717
bson-oid.h
1818
bson-reader.h
19+
bson-cmp.h
1920
bson-string.h
2021
bson-types.h
2122
bson-utf8.h

src/libbson/src/bson/bson-cmp.h

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Copyright 2022 MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "bson-prelude.h"
18+
19+
20+
#ifndef BSON_CMP_H
21+
#define BSON_CMP_H
22+
23+
24+
#include "bson-compat.h" /* ssize_t */
25+
#include "bson-macros.h" /* BSON_CONCAT */
26+
27+
#include <limits.h>
28+
#include <stdbool.h>
29+
#include <stdint.h>
30+
31+
32+
BSON_BEGIN_DECLS
33+
34+
35+
/* Based on the "Safe Integral Comparisons" proposal merged in C++20:
36+
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0586r2.html
37+
*
38+
* Due to lack of type deduction in C, relational comparison functions (e.g.
39+
* `cmp_less`) are defined in sets of four "functions" according to the
40+
* signedness of each value argument, e.g.:
41+
* - bson_cmp_less_ss (signed-value, signed-value)
42+
* - bson_cmp_less_uu (unsigned-value, unsigned-value)
43+
* - bson_cmp_less_su (signed-value, unsigned-value)
44+
* - bson_cmp_less_us (unsigned-value, signed-value)
45+
*
46+
* Similarly, the `in_range` function is defined as a set of two "functions"
47+
* according to the signedness of the value argument:
48+
* - bson_in_range_signed (Type, signed-value)
49+
* - bson_in_range_unsigned (Type, unsigned-value)
50+
*
51+
* The user must take care to use the correct signedness for the provided
52+
* argument(s). Enabling compiler warnings for implicit sign conversions is
53+
* recommended.
54+
*/
55+
56+
57+
#define BSON_CMP_SET(op, ss, uu, su, us) \
58+
static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _ss) (int64_t t, \
59+
int64_t u) \
60+
{ \
61+
return (ss); \
62+
} \
63+
\
64+
static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _uu) (uint64_t t, \
65+
uint64_t u) \
66+
{ \
67+
return (uu); \
68+
} \
69+
\
70+
static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _su) (int64_t t, \
71+
uint64_t u) \
72+
{ \
73+
return (su); \
74+
} \
75+
\
76+
static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _us) (uint64_t t, \
77+
int64_t u) \
78+
{ \
79+
return (us); \
80+
}
81+
82+
BSON_CMP_SET (equal,
83+
t == u,
84+
t == u,
85+
t < 0 ? false : (uint64_t) (t) == u,
86+
u < 0 ? false : t == (uint64_t) (u))
87+
88+
BSON_CMP_SET (not_equal,
89+
!bson_cmp_equal_ss (t, u),
90+
!bson_cmp_equal_uu (t, u),
91+
!bson_cmp_equal_su (t, u),
92+
!bson_cmp_equal_us (t, u))
93+
94+
BSON_CMP_SET (less,
95+
t < u,
96+
t < u,
97+
t < 0 ? true : (uint64_t) (t) < u,
98+
u < 0 ? false : t < (uint64_t) (u))
99+
100+
BSON_CMP_SET (greater,
101+
bson_cmp_less_ss (u, t),
102+
bson_cmp_less_uu (u, t),
103+
bson_cmp_less_us (u, t),
104+
bson_cmp_less_su (u, t))
105+
106+
BSON_CMP_SET (less_equal,
107+
!bson_cmp_greater_ss (t, u),
108+
!bson_cmp_greater_uu (t, u),
109+
!bson_cmp_greater_su (t, u),
110+
!bson_cmp_greater_us (t, u))
111+
112+
BSON_CMP_SET (greater_equal,
113+
!bson_cmp_less_ss (t, u),
114+
!bson_cmp_less_uu (t, u),
115+
!bson_cmp_less_su (t, u),
116+
!bson_cmp_less_us (t, u))
117+
118+
#undef BSON_CMP_SET
119+
120+
121+
/* Define in_range functions for *signed* type Type. */
122+
#define BSON_IN_RANGE_SET_SIGNED(Type, min, max) \
123+
static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _signed) ( \
124+
int64_t value) \
125+
{ \
126+
return bson_cmp_greater_equal_ss (value, min) && \
127+
bson_cmp_less_equal_ss (value, max); \
128+
} \
129+
\
130+
static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _unsigned) ( \
131+
uint64_t value) \
132+
{ \
133+
return bson_cmp_greater_equal_us (value, min) && \
134+
bson_cmp_less_equal_us (value, max); \
135+
}
136+
137+
/* Define in_range functions for *unsigned* type Type. */
138+
#define BSON_IN_RANGE_SET_UNSIGNED(Type, max) \
139+
static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _signed) ( \
140+
int64_t value) \
141+
{ \
142+
return bson_cmp_greater_equal_su (value, 0u) && \
143+
bson_cmp_less_equal_su (value, max); \
144+
} \
145+
\
146+
static BSON_INLINE bool BSON_CONCAT3 (bson_in_range_, Type, _unsigned) ( \
147+
uint64_t value) \
148+
{ \
149+
return bson_cmp_less_equal_uu (value, max); \
150+
}
151+
152+
BSON_IN_RANGE_SET_SIGNED (signed_char, SCHAR_MIN, SCHAR_MAX)
153+
BSON_IN_RANGE_SET_SIGNED (short, SHRT_MIN, SHRT_MAX)
154+
BSON_IN_RANGE_SET_SIGNED (int, INT_MIN, INT_MAX)
155+
BSON_IN_RANGE_SET_SIGNED (long, LONG_MIN, LONG_MAX)
156+
BSON_IN_RANGE_SET_SIGNED (long_long, LLONG_MIN, LLONG_MAX)
157+
158+
BSON_IN_RANGE_SET_UNSIGNED (unsigned_char, UCHAR_MAX)
159+
BSON_IN_RANGE_SET_UNSIGNED (unsigned_short, USHRT_MAX)
160+
BSON_IN_RANGE_SET_UNSIGNED (unsigned_int, UINT_MAX)
161+
BSON_IN_RANGE_SET_UNSIGNED (unsigned_long, ULONG_MAX)
162+
BSON_IN_RANGE_SET_UNSIGNED (unsigned_long_long, ULLONG_MAX)
163+
164+
BSON_IN_RANGE_SET_SIGNED (int8_t, INT8_MIN, INT8_MAX)
165+
BSON_IN_RANGE_SET_SIGNED (int16_t, INT16_MIN, INT16_MAX)
166+
BSON_IN_RANGE_SET_SIGNED (int32_t, INT32_MIN, INT32_MAX)
167+
BSON_IN_RANGE_SET_SIGNED (int64_t, INT64_MIN, INT64_MAX)
168+
169+
BSON_IN_RANGE_SET_UNSIGNED (uint8_t, UINT8_MAX)
170+
BSON_IN_RANGE_SET_UNSIGNED (uint16_t, UINT16_MAX)
171+
BSON_IN_RANGE_SET_UNSIGNED (uint32_t, UINT32_MAX)
172+
BSON_IN_RANGE_SET_UNSIGNED (uint64_t, UINT64_MAX)
173+
174+
BSON_IN_RANGE_SET_SIGNED (ssize_t, SSIZE_MIN, SSIZE_MAX)
175+
BSON_IN_RANGE_SET_UNSIGNED (size_t, SIZE_MAX)
176+
177+
#undef BSON_IN_RANGE_SET_SIGNED
178+
#undef BSON_IN_RANGE_SET_UNSIGNED
179+
180+
181+
/* Return true if the value with *signed* type is in the representable range of
182+
* Type and false otherwise. */
183+
#define bson_in_range_signed(Type, value) \
184+
BSON_CONCAT3 (bson_in_range_, Type, _signed) (value)
185+
186+
/* Return true if the value with *unsigned* type is in the representable range
187+
* of Type and false otherwise. */
188+
#define bson_in_range_unsigned(Type, value) \
189+
BSON_CONCAT3 (bson_in_range_, Type, _unsigned) (value)
190+
191+
192+
BSON_END_DECLS
193+
194+
195+
#endif /* BSON_CMP_H */

src/libbson/src/bson/bson-compat.h

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,157 @@ typedef SSIZE_T ssize_t;
130130
#endif
131131
#endif
132132

133+
/* Derive the maximum representable value of signed integer type T using the
134+
* formula 2^(N - 1) - 1 where N is the number of bits in type T. This assumes
135+
* T is represented using two's complement. */
136+
#define BSON_NUMERIC_LIMITS_MAX_SIGNED(T) \
137+
((T) ((((size_t) 0x01u) << (sizeof (T) * (size_t) CHAR_BIT - 1u)) - 1u))
138+
139+
/* Derive the minimum representable value of signed integer type T as one less
140+
* than the negation of its maximum representable value. This assumes T is
141+
* represented using two's complement. */
142+
#define BSON_NUMERIC_LIMITS_MIN_SIGNED(T, max) ((T) ((-(max)) - 1))
143+
144+
/* Derive the maximum representable value of unsigned integer type T by flipping
145+
* all its bits to 1. */
146+
#define BSON_NUMERIC_LIMITS_MAX_UNSIGNED(T) ((T) (~((T) 0)))
147+
148+
/* Define numeric limit constants if not already available for C90
149+
* compatibility. These can be removed once C99 is declared the minimum
150+
* supported C standard. */
151+
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
152+
153+
#ifndef SCHAR_MAX
154+
#define SCHAR_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (signed char)
155+
#endif
156+
157+
#ifndef SHRT_MAX
158+
#define SHRT_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (short)
159+
#endif
160+
161+
#ifndef INT_MAX
162+
#define INT_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int)
163+
#endif
164+
165+
#ifndef LONG_MAX
166+
#define LONG_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (long)
167+
#endif
168+
169+
#ifndef LLONG_MAX
170+
#define LLONG_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (long long)
171+
#endif
172+
173+
#ifndef UCHAR_MAX
174+
#define UCHAR_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned char)
175+
#endif
176+
177+
#ifndef USHRT_MAX
178+
#define USHRT_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned short)
179+
#endif
180+
181+
#ifndef UINT_MAX
182+
#define UINT_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned int)
183+
#endif
184+
185+
#ifndef ULONG_MAX
186+
#define ULONG_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned long)
187+
#endif
188+
189+
#ifndef ULLONG_MAX
190+
#define ULLONG_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (unsigned long long)
191+
#endif
192+
193+
#ifndef INT8_MAX
194+
#define INT8_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int8_t)
195+
#endif
196+
197+
#ifndef INT16_MAX
198+
#define INT16_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int16_t)
199+
#endif
200+
201+
#ifndef INT32_MAX
202+
#define INT32_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int32_t)
203+
#endif
204+
205+
#ifndef INT64_MAX
206+
#define INT64_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (int64_t)
207+
#endif
208+
209+
#ifndef UINT8_MAX
210+
#define UINT8_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint8_t)
211+
#endif
212+
213+
#ifndef UINT16_MAX
214+
#define UINT16_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint16_t)
215+
#endif
216+
217+
#ifndef UINT32_MAX
218+
#define UINT32_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint32_t)
219+
#endif
220+
221+
#ifndef UINT64_MAX
222+
#define UINT64_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (uint64_t)
223+
#endif
224+
225+
#ifndef SIZE_MAX
226+
#define SIZE_MAX BSON_NUMERIC_LIMITS_MAX_UNSIGNED (size_t)
227+
#endif
228+
229+
#ifndef PTRDIFF_MAX
230+
#define PTRDIFF_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (ptrdiff_t)
231+
#endif
232+
233+
#ifndef SCHAR_MIN
234+
#define SCHAR_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (signed char, SCHAR_MAX)
235+
#endif
236+
237+
#ifndef SHRT_MIN
238+
#define SHRT_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (short, SHRT_MAX)
239+
#endif
240+
241+
#ifndef INT_MIN
242+
#define INT_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int, INT_MAX)
243+
#endif
244+
245+
#ifndef LONG_MIN
246+
#define LONG_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (long, LONG_MAX)
247+
#endif
248+
249+
#ifndef LLONG_MIN
250+
#define LLONG_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (long long, LLONG_MAX)
251+
#endif
252+
253+
#ifndef INT8_MIN
254+
#define INT8_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int8_t, INT8_MAX)
255+
#endif
256+
257+
#ifndef INT16_MIN
258+
#define INT16_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int16_t, INT16_MAX)
259+
#endif
260+
261+
#ifndef INT32_MIN
262+
#define INT32_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int32_t, INT32_MAX)
263+
#endif
264+
265+
#ifndef INT64_MIN
266+
#define INT64_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (int64_t, INT64_MAX)
267+
#endif
268+
269+
#ifndef PTRDIFF_MIN
270+
#define PTRDIFF_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (ptrdiff_t, PTRDIFF_MAX)
271+
#endif
272+
273+
#endif /* !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L */
274+
275+
276+
#ifndef SSIZE_MAX
277+
#define SSIZE_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (ssize_t)
278+
#endif
279+
280+
#ifndef SSIZE_MIN
281+
#define SSIZE_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (ssize_t, SSIZE_MAX)
282+
#endif
283+
133284
#if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT)
134285
#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT
135286
typedef RTL_RUN_ONCE INIT_ONCE;

src/libbson/src/bson/bson.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "bson-macros.h"
2929
#include "bson-config.h"
3030
#include "bson-atomic.h"
31+
#include "bson-cmp.h"
3132
#include "bson-context.h"
3233
#include "bson-clock.h"
3334
#include "bson-decimal128.h"

0 commit comments

Comments
 (0)