mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
It's actually only used in one place in libsystemd and moving it even makes libsystemd smaller (in a non-optimized build): $ ls -l build/libsystemd.so.0.43.0* -rwxr-xr-x 1 zbyszek zbyszek 5763336 Mar 3 09:54 build/libsystemd.so.0.43.0-old -rwxr-xr-x 1 zbyszek zbyszek 5763216 Mar 3 09:54 build/libsystemd.so.0.43.0 Also, move the definitions in the .h file so that similar functions are grouped together and then move the definitions around in the .c file so that they are in the same order as in the header.
172 lines
4.1 KiB
C
172 lines
4.1 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include <malloc.h>
|
|
|
|
#include "alloc-util.h"
|
|
|
|
void* memdup(const void *p, size_t l) {
|
|
void *ret;
|
|
|
|
assert(l == 0 || p);
|
|
|
|
ret = malloc(l ?: 1);
|
|
if (!ret)
|
|
return NULL;
|
|
|
|
return memcpy_safe(ret, p, l);
|
|
}
|
|
|
|
void* memdup_suffix0(const void *p, size_t l) {
|
|
void *ret;
|
|
|
|
assert(l == 0 || p);
|
|
|
|
/* The same as memdup() but place a safety NUL byte after the allocated memory */
|
|
|
|
if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
|
|
return NULL;
|
|
|
|
ret = malloc(l + 1);
|
|
if (!ret)
|
|
return NULL;
|
|
|
|
((uint8_t*) ret)[l] = 0;
|
|
return memcpy_safe(ret, p, l);
|
|
}
|
|
|
|
size_t malloc_sizeof_safe(void **xp) {
|
|
if (_unlikely_(!xp || !*xp))
|
|
return 0;
|
|
|
|
size_t sz = malloc_usable_size(*xp);
|
|
*xp = expand_to_usable(*xp, sz);
|
|
/* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
|
|
* clear that expand_to_usable won't return NULL.
|
|
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
|
|
if (!*xp)
|
|
assert_not_reached();
|
|
return sz;
|
|
}
|
|
|
|
void* expand_to_usable(void *ptr, size_t newsize _unused_) {
|
|
return ptr;
|
|
}
|
|
|
|
void* realloc0(void *p, size_t new_size) {
|
|
size_t old_size;
|
|
void *q;
|
|
|
|
/* Like realloc(), but initializes anything appended to zero */
|
|
|
|
old_size = MALLOC_SIZEOF_SAFE(p);
|
|
|
|
q = realloc(p, new_size);
|
|
if (!q)
|
|
return NULL;
|
|
|
|
new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */
|
|
|
|
if (new_size > old_size)
|
|
memset((uint8_t*) q + old_size, 0, new_size - old_size);
|
|
|
|
return q;
|
|
}
|
|
|
|
void* greedy_realloc(
|
|
void **p,
|
|
size_t need,
|
|
size_t size) {
|
|
|
|
size_t newalloc;
|
|
void *q;
|
|
|
|
assert(p);
|
|
|
|
/* We use malloc_usable_size() for determining the current allocated size. On all systems we care
|
|
* about this should be safe to rely on. Should there ever arise the need to avoid relying on this we
|
|
* can instead locally fall back to realloc() on every call, rounded up to the next exponent of 2 or
|
|
* so. */
|
|
|
|
if (*p && (size == 0 || (MALLOC_SIZEOF_SAFE(*p) / size >= need)))
|
|
return *p;
|
|
|
|
if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
|
|
return NULL;
|
|
newalloc = need * 2;
|
|
|
|
if (!MUL_ASSIGN_SAFE(&newalloc, size))
|
|
return NULL;
|
|
|
|
if (newalloc < 64) /* Allocate at least 64 bytes */
|
|
newalloc = 64;
|
|
|
|
q = realloc(*p, newalloc);
|
|
if (!q)
|
|
return NULL;
|
|
|
|
return *p = q;
|
|
}
|
|
|
|
void* greedy_realloc0(
|
|
void **p,
|
|
size_t need,
|
|
size_t size) {
|
|
|
|
size_t before, after;
|
|
uint8_t *q;
|
|
|
|
assert(p);
|
|
|
|
before = MALLOC_SIZEOF_SAFE(*p); /* malloc_usable_size() will return 0 on NULL input, as per docs */
|
|
|
|
q = greedy_realloc(p, need, size);
|
|
if (!q)
|
|
return NULL;
|
|
|
|
after = MALLOC_SIZEOF_SAFE(q);
|
|
|
|
if (size == 0) /* avoid division by zero */
|
|
before = 0;
|
|
else
|
|
before = (before / size) * size; /* Round down */
|
|
|
|
if (after > before)
|
|
memzero(q + before, after - before);
|
|
|
|
return q;
|
|
}
|
|
|
|
void* greedy_realloc_append(
|
|
void **p,
|
|
size_t *n_p,
|
|
const void *from,
|
|
size_t n_from,
|
|
size_t size) {
|
|
|
|
uint8_t *q;
|
|
|
|
assert(p);
|
|
assert(n_p);
|
|
assert(from || n_from == 0);
|
|
|
|
if (n_from > SIZE_MAX - *n_p)
|
|
return NULL;
|
|
|
|
q = greedy_realloc(p, *n_p + n_from, size);
|
|
if (!q)
|
|
return NULL;
|
|
|
|
memcpy_safe(q + *n_p * size, from, n_from * size);
|
|
|
|
*n_p += n_from;
|
|
|
|
return q;
|
|
}
|
|
|
|
void free_many(void **p, size_t n) {
|
|
assert(p || n == 0);
|
|
|
|
FOREACH_ARRAY(i, p, n)
|
|
*i = mfree(*i);
|
|
}
|