]>
git.ipfire.org Git - thirdparty/openssl.git/blob - include/internal/safe_math.h
85c6147e55c81aa882592232452d58a66f0c7d17
2 * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #ifndef OSSL_INTERNAL_SAFE_MATH_H
11 # define OSSL_INTERNAL_SAFE_MATH_H
14 # include <openssl/e_os2.h> /* For 'ossl_inline' */
16 # ifndef OPENSSL_NO_BUILTIN_OVERFLOW_CHECKING
18 # define has(func) __has_builtin(func)
22 # endif /* OPENSSL_NO_BUILTIN_OVERFLOW_CHECKING */
29 * Safe addition helpers
31 # if has(__builtin_add_overflow)
32 # define OSSL_SAFE_MATH_ADDS(type_name, type, min, max) \
33 static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
39 if (!__builtin_add_overflow(a, b, &r)) \
42 return a < 0 ? min : max; \
45 # define OSSL_SAFE_MATH_ADDU(type_name, type, max) \
46 static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
52 if (!__builtin_add_overflow(a, b, &r)) \
58 # else /* has(__builtin_add_overflow) */
59 # define OSSL_SAFE_MATH_ADDS(type_name, type, min, max) \
60 static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
64 if ((a < 0) ^ (b < 0) \
65 || (a > 0 && b <= max - a) \
66 || (a < 0 && b >= min - a) \
70 return a < 0 ? min : max; \
73 # define OSSL_SAFE_MATH_ADDU(type_name, type, max) \
74 static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
82 # endif /* has(__builtin_add_overflow) */
85 * Safe subtraction helpers
87 # if has(__builtin_sub_overflow)
88 # define OSSL_SAFE_MATH_SUBS(type_name, type, min, max) \
89 static ossl_inline ossl_unused type safe_sub_ ## type_name(type a, \
95 if (!__builtin_sub_overflow(a, b, &r)) \
98 return a < 0 ? min : max; \
101 # else /* has(__builtin_sub_overflow) */
102 # define OSSL_SAFE_MATH_SUBS(type_name, type, min, max) \
103 static ossl_inline ossl_unused type safe_sub_ ## type_name(type a, \
107 if (!((a < 0) ^ (b < 0)) \
108 || (b > 0 && a >= min + b) \
109 || (b < 0 && a <= max + b) \
113 return a < 0 ? min : max; \
116 # endif /* has(__builtin_sub_overflow) */
118 # define OSSL_SAFE_MATH_SUBU(type_name, type) \
119 static ossl_inline ossl_unused type safe_sub_ ## type_name(type a, \
129 * Safe multiplication helpers
131 # if has(__builtin_mul_overflow)
132 # define OSSL_SAFE_MATH_MULS(type_name, type, min, max) \
133 static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
139 if (!__builtin_mul_overflow(a, b, &r)) \
142 return (a < 0) ^ (b < 0) ? min : max; \
145 # define OSSL_SAFE_MATH_MULU(type_name, type, max) \
146 static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
152 if (!__builtin_mul_overflow(a, b, &r)) \
158 # else /* has(__builtin_mul_overflow) */
159 # define OSSL_SAFE_MATH_MULS(type_name, type, min, max) \
160 static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
164 if (a == 0 || b == 0) \
170 if (a != min && b != min) { \
171 const type x = a < 0 ? -a : a; \
172 const type y = b < 0 ? -b : b; \
178 return (a < 0) ^ (b < 0) ? min : max; \
181 # define OSSL_SAFE_MATH_MULU(type_name, type, max) \
182 static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
190 # endif /* has(__builtin_mul_overflow) */
193 * Safe division helpers
195 # define OSSL_SAFE_MATH_DIVS(type_name, type, min, max) \
196 static ossl_inline ossl_unused type safe_div_ ## type_name(type a, \
202 return a < 0 ? min : max; \
204 if (b == -1 && a == min) { \
211 # define OSSL_SAFE_MATH_DIVU(type_name, type, max) \
212 static ossl_inline ossl_unused type safe_div_ ## type_name(type a, \
223 * Safe modulus helpers
225 # define OSSL_SAFE_MATH_MODS(type_name, type, min, max) \
226 static ossl_inline ossl_unused type safe_mod_ ## type_name(type a, \
234 if (b == -1 && a == min) { \
241 # define OSSL_SAFE_MATH_MODU(type_name, type) \
242 static ossl_inline ossl_unused type safe_mod_ ## type_name(type a, \
253 * Safe negation helpers
255 # define OSSL_SAFE_MATH_NEGS(type_name, type, min) \
256 static ossl_inline ossl_unused type safe_neg_ ## type_name(type a, \
265 # define OSSL_SAFE_MATH_NEGU(type_name, type) \
266 static ossl_inline ossl_unused type safe_neg_ ## type_name(type a, \
276 * Safe absolute value helpers
278 # define OSSL_SAFE_MATH_ABSS(type_name, type, min) \
279 static ossl_inline ossl_unused type safe_abs_ ## type_name(type a, \
283 return a < 0 ? -a : a; \
288 # define OSSL_SAFE_MATH_ABSU(type_name, type) \
289 static ossl_inline ossl_unused type safe_abs_ ## type_name(type a, \
296 * Safe fused multiply divide helpers
298 * These are a bit obscure:
299 * . They begin by checking the denominator for zero and getting rid of this
302 * . Second is an attempt to do the multiplication directly, if it doesn't
303 * overflow, the quotient is returned (for signed values there is a
304 * potential problem here which isn't present for unsigned).
306 * . Finally, the multiplication/division is transformed so that the larger
307 * of the numerators is divided first. This requires a remainder
310 * a b / c = (a / c) b + (a mod c) b / c, where a > b
312 * The individual operations need to be overflow checked (again signed
313 * being more problematic).
315 * The algorithm used is not perfect but it should be "good enough".
317 # define OSSL_SAFE_MATH_MULDIVS(type_name, type, max) \
318 static ossl_inline ossl_unused type safe_muldiv_ ## type_name(type a, \
328 return a == 0 || b == 0 ? 0 : max; \
330 x = safe_mul_ ## type_name(a, b, &e2); \
332 return safe_div_ ## type_name(x, c, err); \
338 q = safe_div_ ## type_name(a, c, err); \
339 r = safe_mod_ ## type_name(a, c, err); \
340 x = safe_mul_ ## type_name(r, b, err); \
341 y = safe_mul_ ## type_name(q, b, err); \
342 q = safe_div_ ## type_name(x, c, err); \
343 return safe_add_ ## type_name(y, q, err); \
346 # define OSSL_SAFE_MATH_MULDIVU(type_name, type, max) \
347 static ossl_inline ossl_unused type safe_muldiv_ ## type_name(type a, \
357 return a == 0 || b == 0 ? 0 : max; \
359 x = safe_mul_ ## type_name(a, b, &e2); \
367 x = safe_mul_ ## type_name(a % c, b, err); \
368 y = safe_mul_ ## type_name(a / c, b, err); \
369 return safe_add_ ## type_name(y, x / c, err); \
372 /* Calculate ranges of types */
373 # define OSSL_SAFE_MATH_MINS(type) ((type)1 << (sizeof(type) * 8 - 1))
374 # define OSSL_SAFE_MATH_MAXS(type) (~OSSL_SAFE_MATH_MINS(type))
375 # define OSSL_SAFE_MATH_MAXU(type) (~(type)0)
378 * Wrapper macros to create all the functions of a given type
380 # define OSSL_SAFE_MATH_SIGNED(type_name, type) \
381 OSSL_SAFE_MATH_ADDS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
382 OSSL_SAFE_MATH_MAXS(type)) \
383 OSSL_SAFE_MATH_SUBS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
384 OSSL_SAFE_MATH_MAXS(type)) \
385 OSSL_SAFE_MATH_MULS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
386 OSSL_SAFE_MATH_MAXS(type)) \
387 OSSL_SAFE_MATH_DIVS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
388 OSSL_SAFE_MATH_MAXS(type)) \
389 OSSL_SAFE_MATH_MODS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
390 OSSL_SAFE_MATH_MAXS(type)) \
391 OSSL_SAFE_MATH_MULDIVS(type_name, type, OSSL_SAFE_MATH_MAXS(type)) \
392 OSSL_SAFE_MATH_NEGS(type_name, type, OSSL_SAFE_MATH_MINS(type)) \
393 OSSL_SAFE_MATH_ABSS(type_name, type, OSSL_SAFE_MATH_MINS(type))
395 # define OSSL_SAFE_MATH_UNSIGNED(type_name, type) \
396 OSSL_SAFE_MATH_ADDU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
397 OSSL_SAFE_MATH_SUBU(type_name, type) \
398 OSSL_SAFE_MATH_MULU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
399 OSSL_SAFE_MATH_DIVU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
400 OSSL_SAFE_MATH_MODU(type_name, type) \
401 OSSL_SAFE_MATH_MULDIVU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
402 OSSL_SAFE_MATH_NEGU(type_name, type) \
403 OSSL_SAFE_MATH_ABSU(type_name, type)
405 #endif /* OSSL_INTERNAL_SAFE_MATH_H */