dte test coverage


Directory: ./
File: src/util/xmalloc.h
Date: 2025-05-08 15:05:54
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 14002 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 14002 times.
✗ Branch 2 (3→4) not taken.
✗ Branch 3 (3→6) not taken.
✗ Branch 4 (4→5) not taken.
✓ Branch 5 (4→7) taken 14002 times.
✗ Branch 6 (5→6) not taken.
✗ Branch 7 (5→7) not taken.
14002 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 14002 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 1918 static inline void *xmallocarray(size_t nmemb, size_t size)
43 {
44 1918 return xmalloc(xmul(nmemb, size));
45 }
46
47 RETURNS_NONNULL WARN_UNUSED_RESULT ALLOC_SIZE(2, 3)
48 12079 static inline void *xreallocarray(void *ptr, size_t nmemb, size_t size)
49 {
50 12079 return xrealloc(ptr, xmul(nmemb, size));
51 }
52
53 NONNULL_ARGS_AND_RETURN ALLOC_SIZE(2)
54 4083 static inline void *xmemdup(const void *ptr, size_t size)
55 {
56 4083 return memcpy(xmalloc(size), ptr, size);
57 }
58
59 // Portable version of glibc/FreeBSD mempcpy(3)
60 1805 static inline void *xmempcpy(void *restrict dest, const void *restrict src, size_t n)
61 {
62 1805 memcpy(dest, src, n);
63 1805 return (char*)dest + n;
64 }
65
66 NONNULL_ARGS_AND_RETURN
67 1803 static inline void *xmemjoin(const void *p1, size_t n1, const void *p2, size_t n2)
68 {
69 1803 char *joined = xmalloc(xadd(n1, n2));
70 1803 memcpy(xmempcpy(joined, p1, n1), p2, n2);
71 1803 return joined;
72 }
73
74 NONNULL_ARGS_AND_RETURN
75 1 static inline void *xmemjoin3 (
76 const void *p1, size_t n1,
77 const void *p2, size_t n2,
78 const void *p3, size_t n3
79 ) {
80 1 char *joined = xmalloc(xadd3(n1, n2, n3));
81 1 memcpy(xmempcpy(xmempcpy(joined, p1, n1), p2, n2), p3, n3);
82 1 return joined;
83 }
84
85 XSTRDUP
86 1412 static inline char *xstrjoin(const char *s1, const char *s2)
87 {
88 1412 return xmemjoin(s1, strlen(s1), s2, strlen(s2) + 1);
89 }
90
91 // Return a null-terminated copy of the first `size` bytes of `str`
92 XSTRDUP
93 333 static inline char *xstrcut(const char *str, size_t size)
94 {
95 333 return xmemjoin(str, size, "", 1);
96 }
97
98 // Return a null-terminated copy of the substring between `pos` and `end`
99 XSTRDUP
100 88 static inline char *xstrslice(const char *str, size_t pos, size_t end)
101 {
102 88 BUG_ON(pos > end);
103 88 return xstrcut(str + pos, end - pos);
104 }
105
106 #endif
107