dte test coverage


Directory: ./
File: src/util/arith.h
Date: 2025-06-23 08:41:16
Exec Total Coverage
Lines: 28 28 100.0%
Functions: 11 11 100.0%
Branches: 8 14 57.1%

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 482 static inline bool umax_multiply_overflows(uintmax_t a, uintmax_t b, uintmax_t *result)
29 {
30 482 CHECKED_MUL(a, b, result);
31 }
32
33 15901 static inline bool size_multiply_overflows(size_t a, size_t b, size_t *result)
34 {
35 15901 CHECKED_MUL(a, b, result);
36 }
37
38 476 static inline bool umax_add_overflows(uintmax_t a, uintmax_t b, uintmax_t *result)
39 {
40 476 CHECKED_ADD(a, b, result);
41 }
42
43 245444 static inline bool size_add_overflows(size_t a, size_t b, size_t *result)
44 {
45 245444 CHECKED_ADD(a, b, result);
46 }
47
48 // This is equivalent to `(x + 1) % modulus`, given the constraints
49 // imposed by BUG_ON(), but avoids expensive divisions by a non-constant
50 65 static inline size_t wrapping_increment(size_t x, size_t modulus)
51 {
52 65 BUG_ON(modulus == 0);
53 65 BUG_ON(x >= modulus);
54
2/2
✓ Branch 0 (6→7) taken 49 times.
✓ Branch 1 (6→8) taken 16 times.
65 return (x + 1 < modulus) ? x + 1 : 0;
55 }
56
57 // As above, but for decrementing `x` instead of incrementing it
58 51 static inline size_t wrapping_decrement(size_t x, size_t modulus)
59 {
60 51 BUG_ON(modulus == 0);
61 51 BUG_ON(x >= modulus);
62
2/2
✓ Branch 0 (6→7) taken 37 times.
✓ Branch 1 (6→8) taken 14 times.
51 return (x ? x : modulus) - 1;
63 }
64
65 7 static inline size_t saturating_increment(size_t x, size_t max)
66 {
67 7 BUG_ON(x > max);
68 7 return x + (x < max);
69 }
70
71 5 static inline size_t saturating_decrement(size_t x)
72 {
73 5 return x - (x > 0);
74 }
75
76 12 static inline size_t saturating_subtract(size_t a, size_t b)
77 {
78
2/2
✓ Branch 0 (2→3) taken 6 times.
✓ Branch 1 (2→4) taken 6 times.
12 return (a > b) ? a - b : 0;
79 }
80
81 size_t xmul_(size_t a, size_t b);
82 size_t xadd(size_t a, size_t b);
83
84 // Equivalent to `a * b`, but calling fatal_error() for arithmetic overflow.
85 // Note that if either operand is 2, adding 1 to the result can never
86 // overflow (often useful when doubling a buffer plus 1 extra byte). Similar
87 // observations can be made when multiplying by other powers of 2 (except 1)
88 // due to the equivalence with left shifting.
89 15879 static inline size_t xmul(size_t a, size_t b)
90 {
91 // If either argument is known at compile-time to be 1, the multiplication
92 // can't overflow and is thus safe to be inlined without checks
93
2/8
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 15879 times.
✗ Branch 2 (3→4) not taken.
✗ Branch 3 (3→6) not taken.
✗ Branch 4 (4→5) not taken.
✓ Branch 5 (4→7) taken 15879 times.
✗ Branch 6 (5→6) not taken.
✗ Branch 7 (5→7) not taken.
15879 if ((IS_CT_CONSTANT(a) && a <= 1) || (IS_CT_CONSTANT(b) && b <= 1)) {
94 return a * b; // GCOVR_EXCL_LINE
95 }
96 // Otherwise, emit a call to the checked implementation
97 15879 return xmul_(a, b);
98 }
99
100 4 static inline size_t xadd3(size_t a, size_t b, size_t c)
101 {
102 4 return xadd(a, xadd(b, c));
103 }
104
105 #endif
106