]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/basic/alloc-util.c
ci: enable build/unit test jobs on ppc64le
[thirdparty/systemd.git] / src / basic / alloc-util.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <malloc.h>
4
5#include "alloc-util.h"
6
7void* memdup(const void *p, size_t l) {
8 void *ret;
9
10 assert(l == 0 || p);
11
12 ret = malloc(l ?: 1);
13 if (!ret)
14 return NULL;
15
16 return memcpy_safe(ret, p, l);
17}
18
19void* memdup_suffix0(const void *p, size_t l) {
20 void *ret;
21
22 assert(l == 0 || p);
23
24 /* The same as memdup() but place a safety NUL byte after the allocated memory */
25
26 if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
27 return NULL;
28
29 ret = malloc(l + 1);
30 if (!ret)
31 return NULL;
32
33 ((uint8_t*) ret)[l] = 0;
34 return memcpy_safe(ret, p, l);
35}
36
37void* greedy_realloc(
38 void **p,
39 size_t need,
40 size_t size) {
41
42 size_t newalloc;
43 void *q;
44
45 assert(p);
46
47 /* We use malloc_usable_size() for determining the current allocated size. On all systems we care
48 * about this should be safe to rely on. Should there ever arise the need to avoid relying on this we
49 * can instead locally fall back to realloc() on every call, rounded up to the next exponent of 2 or
50 * so. */
51
52 if (*p && (size == 0 || (MALLOC_SIZEOF_SAFE(*p) / size >= need)))
53 return *p;
54
55 if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
56 return NULL;
57 newalloc = need * 2;
58
59 if (!MUL_ASSIGN_SAFE(&newalloc, size))
60 return NULL;
61
62 if (newalloc < 64) /* Allocate at least 64 bytes */
63 newalloc = 64;
64
65 q = realloc(*p, newalloc);
66 if (!q)
67 return NULL;
68
69 return *p = q;
70}
71
72void* greedy_realloc0(
73 void **p,
74 size_t need,
75 size_t size) {
76
77 size_t before, after;
78 uint8_t *q;
79
80 assert(p);
81
82 before = MALLOC_SIZEOF_SAFE(*p); /* malloc_usable_size() will return 0 on NULL input, as per docs */
83
84 q = greedy_realloc(p, need, size);
85 if (!q)
86 return NULL;
87
88 after = MALLOC_SIZEOF_SAFE(q);
89
90 if (size == 0) /* avoid division by zero */
91 before = 0;
92 else
93 before = (before / size) * size; /* Round down */
94
95 if (after > before)
96 memzero(q + before, after - before);
97
98 return q;
99}
100
101void* greedy_realloc_append(
102 void **p,
103 size_t *n_p,
104 const void *from,
105 size_t n_from,
106 size_t size) {
107
108 uint8_t *q;
109
110 assert(p);
111 assert(n_p);
112 assert(from || n_from == 0);
113
114 if (n_from > SIZE_MAX - *n_p)
115 return NULL;
116
117 q = greedy_realloc(p, *n_p + n_from, size);
118 if (!q)
119 return NULL;
120
121 memcpy_safe(q + *n_p * size, from, n_from * size);
122
123 *n_p += n_from;
124
125 return q;
126}
127
128void *expand_to_usable(void *ptr, size_t newsize _unused_) {
129 return ptr;
130}
131
132size_t malloc_sizeof_safe(void **xp) {
133 if (_unlikely_(!xp || !*xp))
134 return 0;
135
136 size_t sz = malloc_usable_size(*xp);
137 *xp = expand_to_usable(*xp, sz);
138 /* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
139 * clear that expand_to_usable won't return NULL.
140 * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
141 if (!*xp)
142 assert_not_reached();
143 return sz;
144}