]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/alloc-util.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / basic / alloc-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
b5efdb8a 2
e5905427 3#include <malloc.h>
11c3a366
TA
4#include <stdint.h>
5#include <string.h>
6
b5efdb8a 7#include "alloc-util.h"
11c3a366 8#include "macro.h"
0a970718 9#include "memory-util.h"
b5efdb8a
LP
10
11void* memdup(const void *p, size_t l) {
c165d97d 12 void *ret;
b5efdb8a 13
c165d97d
LP
14 assert(l == 0 || p);
15
830464c3 16 ret = malloc(l ?: 1);
c165d97d
LP
17 if (!ret)
18 return NULL;
19
20 memcpy(ret, p, l);
21 return ret;
22}
23
d40c54fe 24void* memdup_suffix0(const void *p, size_t l) {
c165d97d
LP
25 void *ret;
26
27 assert(l == 0 || p);
28
29 /* The same as memdup() but place a safety NUL byte after the allocated memory */
b5efdb8a 30
e5e21a05
LP
31 if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
32 return NULL;
33
c165d97d
LP
34 ret = malloc(l + 1);
35 if (!ret)
b5efdb8a
LP
36 return NULL;
37
c165d97d
LP
38 *((uint8_t*) mempcpy(ret, p, l)) = 0;
39 return ret;
b5efdb8a
LP
40}
41
42void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
43 size_t a, newalloc;
44 void *q;
45
46 assert(p);
47 assert(allocated);
48
49 if (*allocated >= need)
50 return *p;
51
23964f7f
LP
52 if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
53 return NULL;
b5efdb8a 54
23964f7f
LP
55 newalloc = need * 2;
56 if (size_multiply_overflow(newalloc, size))
b5efdb8a
LP
57 return NULL;
58
23964f7f
LP
59 a = newalloc * size;
60 if (a < 64) /* Allocate at least 64 bytes */
61 a = 64;
62
b5efdb8a
LP
63 q = realloc(*p, a);
64 if (!q)
65 return NULL;
66
e5905427
LP
67 if (size > 0) {
68 size_t bn;
69
70 /* Adjust for the 64 byte minimum */
71 newalloc = a / size;
72
73 bn = malloc_usable_size(q) / size;
74 if (bn > newalloc) {
75 void *qq;
76
77 /* The actual size allocated is larger than what we asked for. Let's call realloc() again to
78 * take possession of the extra space. This should be cheap, since libc doesn't have to move
79 * the memory for this. */
80
38288f0b 81 qq = reallocarray(q, bn, size);
e5905427
LP
82 if (_likely_(qq)) {
83 *p = qq;
84 *allocated = bn;
85 return qq;
86 }
87 }
88 }
89
b5efdb8a 90 *p = q;
fcc72fd0 91 *allocated = newalloc;
b5efdb8a
LP
92 return q;
93}
94
95void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
96 size_t prev;
97 uint8_t *q;
98
99 assert(p);
100 assert(allocated);
101
102 prev = *allocated;
103
104 q = greedy_realloc(p, allocated, need, size);
105 if (!q)
106 return NULL;
107
108 if (*allocated > prev)
109 memzero(q + prev * size, (*allocated - prev) * size);
110
111 return q;
112}