]>
Commit | Line | Data |
---|---|---|
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 | |
11 | void* 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 | 24 | void* 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 | ||
42 | void* 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 | ||
95 | void* 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 | } |