diff options
| author | Sebastien Bacher <seb128@ubuntu.com> | 2019-01-25 11:26:25 +0100 |
|---|---|---|
| committer | Sebastien Bacher <seb128@ubuntu.com> | 2019-01-25 11:26:25 +0100 |
| commit | f54a568880bf47c2ea54c9b30d291156b34d6539 (patch) | |
| tree | aab9bb44b306da7651e8caf38bbab5cfeeb81b7d /shared/systemd/src/basic/alloc-util.h | |
| parent | e8ac7dacdcf4b38addef4f8ac6ab038f9d29582c (diff) | |
| parent | bbae86d3d2997a853ca0365e8eb7a3ca7489ee09 (diff) | |
Update upstream source from tag 'upstream/1.15.2'
Update to upstream version '1.15.2' with Debian dir b4be4b7cfce96679a31cb9d423107789761e3b49
Diffstat (limited to 'shared/systemd/src/basic/alloc-util.h')
| -rw-r--r-- | shared/systemd/src/basic/alloc-util.h | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h new file mode 100644 index 00000000..ff7a4679 --- /dev/null +++ b/shared/systemd/src/basic/alloc-util.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <alloca.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" + +typedef void (*free_func_t)(void *p); + +#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) + +#define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t))) + +#define newa(t, n) \ + ({ \ + assert(!size_multiply_overflow(sizeof(t), n)); \ + (t*) alloca(sizeof(t)*(n)); \ + }) + +#define newa0(t, n) \ + ({ \ + assert(!size_multiply_overflow(sizeof(t), n)); \ + (t*) alloca0(sizeof(t)*(n)); \ + }) + +#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) + +#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) + +#define malloc0(n) (calloc(1, (n))) + +static inline void *mfree(void *memory) { + free(memory); + return NULL; +} + +#define free_and_replace(a, b) \ + ({ \ + free(a); \ + (a) = (b); \ + (b) = NULL; \ + 0; \ + }) + +void* memdup(const void *p, size_t l) _alloc_(2); +void* memdup_suffix0(const void *p, size_t l) _alloc_(2); + +#define memdupa(p, l) \ + ({ \ + void *_q_; \ + _q_ = alloca(l); \ + memcpy(_q_, p, l); \ + }) + +#define memdupa_suffix0(p, l) \ + ({ \ + void *_q_; \ + _q_ = alloca(l + 1); \ + ((uint8_t*) _q_)[l] = 0; \ + memcpy(_q_, p, l); \ + }) + +static inline void freep(void *p) { + free(*(void**) p); +} + +#define _cleanup_free_ _cleanup_(freep) + +static inline bool size_multiply_overflow(size_t size, size_t need) { + return _unlikely_(need != 0 && size > (SIZE_MAX / need)); +} + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { + if (size_multiply_overflow(size, need)) + return NULL; + + return malloc(size * need ?: 1); +} + +#if !HAVE_REALLOCARRAY +_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { + if (size_multiply_overflow(size, need)) + return NULL; + + return realloc(p, size * need ?: 1); +} +#endif + +_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { + if (size_multiply_overflow(size, need)) + return NULL; + + return memdup(p, size * need); +} + +_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { + if (size_multiply_overflow(size, need)) + return NULL; + + return memdup_suffix0(p, size * need); +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); + +#define GREEDY_REALLOC(array, allocated, need) \ + greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define GREEDY_REALLOC0(array, allocated, need) \ + greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define alloca0(n) \ + ({ \ + char *_new_; \ + size_t _len_ = n; \ + _new_ = alloca(_len_); \ + (void *) memset(_new_, 0, _len_); \ + }) + +/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ +#define alloca_align(size, align) \ + ({ \ + void *_ptr_; \ + size_t _mask_ = (align) - 1; \ + _ptr_ = alloca((size) + _mask_); \ + (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ + }) + +#define alloca0_align(size, align) \ + ({ \ + void *_new_; \ + size_t _size_ = (size); \ + _new_ = alloca_align(_size_, (align)); \ + (void*)memset(_new_, 0, _size_); \ + }) + +/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to + * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ +#define TAKE_PTR(ptr) \ + ({ \ + typeof(ptr) _ptr_ = (ptr); \ + (ptr) = NULL; \ + _ptr_; \ + }) |