dte test coverage


Directory: ./
File: src/util/xmalloc.h
Date: 2025-06-04 06:50:24
Exec Total Coverage
Lines: 29 29 100.0%
Functions: 11 11 100.0%
Branches: 2 8 25.0%

Line Branch Exec Source
1 #ifndef UTIL_XMALLOC_H
2 #define UTIL_XMALLOC_H
3
4 #include <stddef.h>
5 #include <string.h>
6 #include "arith.h"
7 #include "macros.h"
8
9 #define XMEMDUP(ptr) xmemdup(ptr, sizeof(*ptr))
10 #define xrenew(mem, n) xreallocarray(mem, (n), sizeof(*mem))
11
12 void *xmalloc(size_t size) XMALLOC ALLOC_SIZE(1);
13 void *xcalloc(size_t nmemb, size_t size) XMALLOC ALLOC_SIZE(1, 2);
14 void *xrealloc(void *ptr, size_t size) RETURNS_NONNULL WARN_UNUSED_RESULT ALLOC_SIZE(2);
15 char *xstrdup(const char *str) XSTRDUP;
16 char *xasprintf(const char *format, ...) PRINTF(1) XMALLOC;
17 size_t xmul_(size_t a, size_t b);
18 size_t xadd(size_t a, size_t b);
19
20 // Equivalent to `a * b`, but calling fatal_error() for arithmetic overflow.
21 // Note that if either operand is 2, adding 1 to the result can never
22 // overflow (often useful when doubling a buffer plus 1 extra byte). Similar
23 // observations can be made when multiplying by other powers of 2 (except 1)
24 // due to the equivalence with left shifting.
25 14459 static inline size_t xmul(size_t a, size_t b)
26 {
27 // If either argument is known at compile-time to be 1, the multiplication
28 // can't overflow and is thus safe to be inlined without checks
29
2/8
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 14459 times.
✗ Branch 2 (3→4) not taken.
✗ Branch 3 (3→6) not taken.
✗ Branch 4 (4→5) not taken.
✓ Branch 5 (4→7) taken 14459 times.
✗ Branch 6 (5→6) not taken.
✗ Branch 7 (5→7) not taken.
14459 if ((IS_CT_CONSTANT(a) && a <= 1) || (IS_CT_CONSTANT(b) && b <= 1)) {
30 return a * b; // GCOVR_EXCL_LINE
31 }
32 // Otherwise, emit a call to the checked implementation
33 14459 return xmul_(a, b);
34 }
35
36 4 static inline size_t xadd3(size_t a, size_t b, size_t c)
37 {
38 4 return xadd(a, xadd(b, c));
39 }
40
41 XMALLOC ALLOC_SIZE(1, 2)
42 1919 static inline void *xmallocarray(size_t nmemb, size_t size)
43 {
44 1919 return xmalloc(xmul(nmemb, size));
45 }
46
47 RETURNS_NONNULL WARN_UNUSED_RESULT ALLOC_SIZE(2, 3)
48 12516 static inline void *xreallocarray(void *ptr, size_t nmemb, size_t size)
49 {
50 12516 return xrealloc(ptr, xmul(nmemb, size));
51 }
52
53 NONNULL_ARGS_AND_RETURN ALLOC_SIZE(2)
54 4096 static inline void *xmemdup(const void *ptr, size_t size)
55 {
56 4096 return memcpy(xmalloc(size), ptr, size);
57 }
58
59 // Portable version of glibc/FreeBSD mempcpy(3)
60 NONNULL_ARGS_AND_RETURN
61 2206 static inline void *xmempcpy(void *restrict dest, const void *restrict src, size_t n)
62 {
63 2206 memcpy(dest, src, n);
64 2206 return (char*)dest + n;
65 }
66
67 NONNULL_ARGS_AND_RETURN
68 1803 static inline void *xmemjoin(const void *p1, size_t n1, const void *p2, size_t n2)
69 {
70 1803 char *joined = xmalloc(xadd(n1, n2));
71 1803 memcpy(xmempcpy(joined, p1, n1), p2, n2);
72 1803 return joined;
73 }
74
75 NONNULL_ARGS_AND_RETURN
76 1 static inline void *xmemjoin3 (
77 const void *p1, size_t n1,
78 const void *p2, size_t n2,
79 const void *p3, size_t n3
80 ) {
81 1 char *joined = xmalloc(xadd3(n1, n2, n3));
82 1 memcpy(xmempcpy(xmempcpy(joined, p1, n1), p2, n2), p3, n3);
83 1 return joined;
84 }
85
86 XSTRDUP
87 1412 static inline char *xstrjoin(const char *s1, const char *s2)
88 {
89 1412 return xmemjoin(s1, strlen(s1), s2, strlen(s2) + 1);
90 }
91
92 // Return a null-terminated copy of the first `size` bytes of `str`
93 XSTRDUP
94 333 static inline char *xstrcut(const char *str, size_t size)
95 {
96 333 return xmemjoin(str, size, "", 1);
97 }
98
99 // Return a null-terminated copy of the substring between `pos` and `end`
100 XSTRDUP
101 88 static inline char *xstrslice(const char *str, size_t pos, size_t end)
102 {
103 88 BUG_ON(pos > end);
104 88 return xstrcut(str + pos, end - pos);
105 }
106
107 #endif
108