]> git.proxmox.com Git - systemd.git/blob - src/basic/alloc-util.h
New upstream version 240
[systemd.git] / src / basic / alloc-util.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 #pragma once
3
4 #include <alloca.h>
5 #include <stddef.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "macro.h"
10
11 typedef void (*free_func_t)(void *p);
12
13 #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
14
15 #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
16
17 #define newa(t, n) \
18 ({ \
19 assert(!size_multiply_overflow(sizeof(t), n)); \
20 (t*) alloca(sizeof(t)*(n)); \
21 })
22
23 #define newa0(t, n) \
24 ({ \
25 assert(!size_multiply_overflow(sizeof(t), n)); \
26 (t*) alloca0(sizeof(t)*(n)); \
27 })
28
29 #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
30
31 #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
32
33 #define malloc0(n) (calloc(1, (n)))
34
35 static inline void *mfree(void *memory) {
36 free(memory);
37 return NULL;
38 }
39
40 #define free_and_replace(a, b) \
41 ({ \
42 free(a); \
43 (a) = (b); \
44 (b) = NULL; \
45 0; \
46 })
47
48 void* memdup(const void *p, size_t l) _alloc_(2);
49 void* memdup_suffix0(const void *p, size_t l) _alloc_(2);
50
51 #define memdupa(p, l) \
52 ({ \
53 void *_q_; \
54 _q_ = alloca(l); \
55 memcpy(_q_, p, l); \
56 })
57
58 #define memdupa_suffix0(p, l) \
59 ({ \
60 void *_q_; \
61 _q_ = alloca(l + 1); \
62 ((uint8_t*) _q_)[l] = 0; \
63 memcpy(_q_, p, l); \
64 })
65
66 static inline void freep(void *p) {
67 free(*(void**) p);
68 }
69
70 #define _cleanup_free_ _cleanup_(freep)
71
72 static inline bool size_multiply_overflow(size_t size, size_t need) {
73 return _unlikely_(need != 0 && size > (SIZE_MAX / need));
74 }
75
76 _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
77 if (size_multiply_overflow(size, need))
78 return NULL;
79
80 return malloc(size * need ?: 1);
81 }
82
83 #if !HAVE_REALLOCARRAY
84 _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
85 if (size_multiply_overflow(size, need))
86 return NULL;
87
88 return realloc(p, size * need ?: 1);
89 }
90 #endif
91
92 _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
93 if (size_multiply_overflow(size, need))
94 return NULL;
95
96 return memdup(p, size * need);
97 }
98
99 _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
100 if (size_multiply_overflow(size, need))
101 return NULL;
102
103 return memdup_suffix0(p, size * need);
104 }
105
106 void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
107 void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
108
109 #define GREEDY_REALLOC(array, allocated, need) \
110 greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
111
112 #define GREEDY_REALLOC0(array, allocated, need) \
113 greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
114
115 #define alloca0(n) \
116 ({ \
117 char *_new_; \
118 size_t _len_ = n; \
119 _new_ = alloca(_len_); \
120 (void *) memset(_new_, 0, _len_); \
121 })
122
123 /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
124 #define alloca_align(size, align) \
125 ({ \
126 void *_ptr_; \
127 size_t _mask_ = (align) - 1; \
128 _ptr_ = alloca((size) + _mask_); \
129 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
130 })
131
132 #define alloca0_align(size, align) \
133 ({ \
134 void *_new_; \
135 size_t _size_ = (size); \
136 _new_ = alloca_align(_size_, (align)); \
137 (void*)memset(_new_, 0, _size_); \
138 })
139
140 /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
141 * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
142 #define TAKE_PTR(ptr) \
143 ({ \
144 typeof(ptr) _ptr_ = (ptr); \
145 (ptr) = NULL; \
146 _ptr_; \
147 })