| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef UTIL_ARITH_H | ||
| 2 | #define UTIL_ARITH_H | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <stddef.h> | ||
| 6 | #include <stdint.h> | ||
| 7 | #include "debug.h" | ||
| 8 | #include "macros.h" | ||
| 9 | |||
| 10 | // Calculate the maximum representable value for __typeof__(x), where x | ||
| 11 | // is an unsigned integer and sizeof(x) >= sizeof(int) | ||
| 12 | #define UNSIGNED_MAX_VALUE(x) (~((x) ^ (x))) | ||
| 13 | |||
| 14 | #if GNUC_AT_LEAST(5, 0) || HAS_BUILTIN(__builtin_mul_overflow) | ||
| 15 | #define CHECKED_ADD(a, b, res) return __builtin_add_overflow(a, b, res) | ||
| 16 | #define CHECKED_MUL(a, b, res) return __builtin_mul_overflow(a, b, res) | ||
| 17 | #elif __STDC_VERSION__ >= 202311L | ||
| 18 | #include <stdckdint.h> | ||
| 19 | #define CHECKED_ADD(a, b, res) return ckd_add(res, a, b) | ||
| 20 | #define CHECKED_MUL(a, b, res) return ckd_mul(res, a, b) | ||
| 21 | #else | ||
| 22 | #define CHECKED_ADD(a, b, res) \ | ||
| 23 | if (unlikely(b > UNSIGNED_MAX_VALUE(a) - a)) return true; else {*res = a + b; return false;} | ||
| 24 | #define CHECKED_MUL(a, b, res) \ | ||
| 25 | if (unlikely(a > 0 && b > UNSIGNED_MAX_VALUE(a) / a)) return true; else {*res = a * b; return false;} | ||
| 26 | #endif | ||
| 27 | |||
| 28 | 488 | static inline bool umax_multiply_overflows(uintmax_t a, uintmax_t b, uintmax_t *result) | |
| 29 | { | ||
| 30 | 488 | CHECKED_MUL(a, b, result); | |
| 31 | } | ||
| 32 | |||
| 33 | 16050 | static inline bool size_multiply_overflows(size_t a, size_t b, size_t *result) | |
| 34 | { | ||
| 35 | 16050 | CHECKED_MUL(a, b, result); | |
| 36 | } | ||
| 37 | |||
| 38 | 482 | static inline bool umax_add_overflows(uintmax_t a, uintmax_t b, uintmax_t *result) | |
| 39 | { | ||
| 40 | 482 | CHECKED_ADD(a, b, result); | |
| 41 | } | ||
| 42 | |||
| 43 | 256710 | static inline bool size_add_overflows(size_t a, size_t b, size_t *result) | |
| 44 | { | ||
| 45 | 256710 | CHECKED_ADD(a, b, result); | |
| 46 | } | ||
| 47 | |||
| 48 | // Return true if `nmemb * size` overflows and the compiler indicates a | ||
| 49 | // pre-C23 standards revision. The purpose of this is to check for integer | ||
| 50 | // overflow in the product of calloc() arguments, but only when the standard | ||
| 51 | // doesn't require the calloc() function itself to do so (see ยง7.24.3.2p3). | ||
| 52 | 4389 | static inline bool calloc_args_have_ub_overflow(size_t nmemb, size_t size) | |
| 53 | { | ||
| 54 | 4389 | bool pre_c23 = (__STDC_VERSION__ < 202311L); | |
| 55 | 4389 | size_t tmp; | |
| 56 | 4389 | return pre_c23 && size_multiply_overflows(nmemb, size, &tmp); | |
| 57 | } | ||
| 58 | |||
| 59 | // This is equivalent to `(x + 1) % modulus`, given the constraints | ||
| 60 | // imposed by BUG_ON(), but avoids expensive divisions by a non-constant | ||
| 61 | 65 | static inline size_t wrapping_increment(size_t x, size_t modulus) | |
| 62 | { | ||
| 63 | 65 | BUG_ON(modulus == 0); | |
| 64 | 65 | BUG_ON(x >= modulus); | |
| 65 |
2/2✓ Branch 0 (6→7) taken 49 times.
✓ Branch 1 (6→8) taken 16 times.
|
65 | return (x + 1 < modulus) ? x + 1 : 0; |
| 66 | } | ||
| 67 | |||
| 68 | // As above, but for decrementing `x` instead of incrementing it | ||
| 69 | 51 | static inline size_t wrapping_decrement(size_t x, size_t modulus) | |
| 70 | { | ||
| 71 | 51 | BUG_ON(modulus == 0); | |
| 72 | 51 | BUG_ON(x >= modulus); | |
| 73 |
2/2✓ Branch 0 (6→7) taken 37 times.
✓ Branch 1 (6→8) taken 14 times.
|
51 | return (x ? x : modulus) - 1; |
| 74 | } | ||
| 75 | |||
| 76 | 7 | static inline size_t saturating_increment(size_t x, size_t max) | |
| 77 | { | ||
| 78 | 7 | BUG_ON(x > max); | |
| 79 | 7 | return x + (x < max); | |
| 80 | } | ||
| 81 | |||
| 82 | 5 | static inline size_t saturating_decrement(size_t x) | |
| 83 | { | ||
| 84 | 5 | return x - (x > 0); | |
| 85 | } | ||
| 86 | |||
| 87 | 12 | static inline size_t saturating_subtract(size_t a, size_t b) | |
| 88 | { | ||
| 89 | 12 | return a - MIN(a, b); | |
| 90 | } | ||
| 91 | |||
| 92 | size_t xmul_(size_t a, size_t b); | ||
| 93 | size_t xadd(size_t a, size_t b); | ||
| 94 | |||
| 95 | // Equivalent to `a * b`, but calling fatal_error() for arithmetic overflow. | ||
| 96 | // Note that if either operand is 2, adding 1 to the result can never | ||
| 97 | // overflow (often useful when doubling a buffer plus 1 extra byte). Similar | ||
| 98 | // observations can be made when multiplying by other powers of 2 (except 1) | ||
| 99 | // due to the equivalence with left shifting. | ||
| 100 | 16028 | static inline size_t xmul(size_t a, size_t b) | |
| 101 | { | ||
| 102 | // If either argument is known at compile-time to be 1, the multiplication | ||
| 103 | // can't overflow and is thus safe to be inlined without checks | ||
| 104 |
2/8✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 16028 times.
✗ Branch 2 (3→4) not taken.
✗ Branch 3 (3→6) not taken.
✗ Branch 4 (4→5) not taken.
✓ Branch 5 (4→7) taken 16028 times.
✗ Branch 6 (5→6) not taken.
✗ Branch 7 (5→7) not taken.
|
16028 | if ((IS_CT_CONSTANT(a) && a <= 1) || (IS_CT_CONSTANT(b) && b <= 1)) { |
| 105 | − | return a * b; // GCOVR_EXCL_LINE | |
| 106 | } | ||
| 107 | // Otherwise, emit a call to the checked implementation | ||
| 108 | 16028 | return xmul_(a, b); | |
| 109 | } | ||
| 110 | |||
| 111 | 6917 | static inline size_t xadd3(size_t a, size_t b, size_t c) | |
| 112 | { | ||
| 113 | 6917 | return xadd(a, xadd(b, c)); | |
| 114 | } | ||
| 115 | |||
| 116 | #endif | ||
| 117 |