1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <malloc.h>
4 #include <stdint.h>
5
6 #include "alloc-util.h"
7 #include "macro.h"
8 #include "memory-util.h"
9 #include "random-util.h"
10 #include "tests.h"
11
TEST(alloca)12 TEST(alloca) {
13 static const uint8_t zero[997] = { };
14 char *t;
15
16 t = alloca_align(17, 512);
17 assert_se(!((uintptr_t)t & 0xff));
18 memzero(t, 17);
19
20 t = alloca0_align(997, 1024);
21 assert_se(!((uintptr_t)t & 0x1ff));
22 assert_se(!memcmp(t, zero, 997));
23 }
24
TEST(GREEDY_REALLOC)25 TEST(GREEDY_REALLOC) {
26 _cleanup_free_ int *a = NULL, *b = NULL;
27 size_t i, j;
28
29 /* Give valgrind a chance to verify our realloc() operations */
30
31 for (i = 0; i < 20480; i++) {
32 assert_se(GREEDY_REALLOC(a, i + 1));
33 assert_se(MALLOC_ELEMENTSOF(a) >= i + 1);
34 assert_se(MALLOC_SIZEOF_SAFE(a) >= (i + 1) * sizeof(int));
35 a[i] = (int) i;
36 assert_se(GREEDY_REALLOC(a, i / 2));
37 assert_se(MALLOC_ELEMENTSOF(a) >= i / 2);
38 assert_se(MALLOC_SIZEOF_SAFE(a) >= (i / 2) * sizeof(int));
39 }
40
41 for (j = 0; j < i / 2; j++)
42 assert_se(a[j] == (int) j);
43
44 for (i = 30; i < 20480; i += 7) {
45 assert_se(GREEDY_REALLOC(b, i + 1));
46 assert_se(MALLOC_ELEMENTSOF(b) >= i + 1);
47 assert_se(MALLOC_SIZEOF_SAFE(b) >= (i + 1) * sizeof(int));
48 b[i] = (int) i;
49 assert_se(GREEDY_REALLOC(b, i / 2));
50 assert_se(MALLOC_ELEMENTSOF(b) >= i / 2);
51 assert_se(MALLOC_SIZEOF_SAFE(b) >= (i / 2) * sizeof(int));
52 }
53
54 for (j = 30; j < i / 2; j += 7)
55 assert_se(b[j] == (int) j);
56 }
57
TEST(memdup_multiply_and_greedy_realloc)58 TEST(memdup_multiply_and_greedy_realloc) {
59 static const int org[] = { 1, 2, 3 };
60 _cleanup_free_ int *dup;
61 size_t i;
62 int *p;
63
64 dup = memdup_suffix0_multiply(org, sizeof(int), 3);
65 assert_se(dup);
66 assert_se(dup[0] == 1);
67 assert_se(dup[1] == 2);
68 assert_se(dup[2] == 3);
69 assert_se(((uint8_t*) dup)[sizeof(int) * 3] == 0);
70 free(dup);
71
72 dup = memdup_multiply(org, sizeof(int), 3);
73 assert_se(dup);
74 assert_se(dup[0] == 1);
75 assert_se(dup[1] == 2);
76 assert_se(dup[2] == 3);
77
78 memzero(dup + 3, malloc_usable_size(dup) - sizeof(int) * 3);
79
80 p = dup;
81 assert_se(GREEDY_REALLOC0(dup, 2) == p);
82
83 p = GREEDY_REALLOC0(dup, 10);
84 assert_se(p == dup);
85 assert_se(MALLOC_ELEMENTSOF(p) >= 10);
86 assert_se(p[0] == 1);
87 assert_se(p[1] == 2);
88 assert_se(p[2] == 3);
89 for (i = 3; i < MALLOC_ELEMENTSOF(p); i++)
90 assert_se(p[i] == 0);
91 }
92
TEST(bool_assign)93 TEST(bool_assign) {
94 bool b, c, *cp = &c, d, e, f, g, h;
95
96 b = 123;
97 *cp = -11;
98 d = 0xF & 0xFF;
99 e = b & d;
100 f = 0x0;
101 g = cp; /* cast from pointer */
102 h = NULL; /* cast from pointer */
103
104 assert_se(b);
105 assert_se(c);
106 assert_se(d);
107 assert_se(e);
108 assert_se(!f);
109 assert_se(g);
110 assert_se(!h);
111 }
112
113 static int cleanup_counter = 0;
114
cleanup1(void * a)115 static void cleanup1(void *a) {
116 log_info("%s(%p)", __func__, a);
117 assert_se(++cleanup_counter == *(int*) a);
118 }
cleanup2(void * a)119 static void cleanup2(void *a) {
120 log_info("%s(%p)", __func__, a);
121 assert_se(++cleanup_counter == *(int*) a);
122 }
cleanup3(void * a)123 static void cleanup3(void *a) {
124 log_info("%s(%p)", __func__, a);
125 assert_se(++cleanup_counter == *(int*) a);
126 }
127
TEST(cleanup_order)128 TEST(cleanup_order) {
129 _cleanup_(cleanup1) int x1 = 4, x2 = 3;
130 _cleanup_(cleanup3) int z = 2;
131 _cleanup_(cleanup2) int y = 1;
132 log_debug("x1: %p", &x1);
133 log_debug("x2: %p", &x2);
134 log_debug("y: %p", &y);
135 log_debug("z: %p", &z);
136 }
137
TEST(auto_erase_memory)138 TEST(auto_erase_memory) {
139 _cleanup_(erase_and_freep) uint8_t *p1, *p2;
140
141 /* print address of p2, else e.g. clang-11 will optimize it out */
142 log_debug("p1: %p p2: %p", &p1, &p2);
143
144 assert_se(p1 = new(uint8_t, 4703)); /* use prime size, to ensure that there will be free space at the
145 * end of the allocation, since malloc() enforces alignment */
146 assert_se(p2 = new(uint8_t, 4703));
147
148 assert_se(genuine_random_bytes(p1, 4703, RANDOM_BLOCK) == 0);
149
150 /* before we exit the scope, do something with this data, so that the compiler won't optimize this away */
151 memcpy(p2, p1, 4703);
152 for (size_t i = 0; i < 4703; i++)
153 assert_se(p1[i] == p2[i]);
154 }
155
156 #define TEST_SIZES(f, n) \
157 do { \
158 log_debug("requested=%zu vs. malloc_size=%zu vs. gcc_size=%zu", \
159 n * sizeof(*f), \
160 malloc_usable_size(f), \
161 __builtin_object_size(f, 0)); \
162 assert_se(MALLOC_ELEMENTSOF(f) >= n); \
163 assert_se(MALLOC_SIZEOF_SAFE(f) >= sizeof(*f) * n); \
164 assert_se(malloc_usable_size(f) >= sizeof(*f) * n); \
165 assert_se(__builtin_object_size(f, 0) >= sizeof(*f) * n); \
166 } while (false)
167
TEST(malloc_size_safe)168 TEST(malloc_size_safe) {
169 _cleanup_free_ uint32_t *f = NULL;
170 size_t n = 4711;
171
172 /* Let's check the macros and built-ins work on NULL and return the expected values */
173 assert_se(MALLOC_ELEMENTSOF((float*) NULL) == 0);
174 assert_se(MALLOC_SIZEOF_SAFE((float*) NULL) == 0);
175 assert_se(malloc_usable_size(NULL) == 0); /* as per man page, this is safe and defined */
176 assert_se(__builtin_object_size(NULL, 0) == SIZE_MAX); /* as per docs SIZE_MAX is returned for pointers where the size isn't known */
177
178 /* Then, let's try these macros once with constant size values, so that __builtin_object_size()
179 * definitely can work (as long as -O2 is used when compiling) */
180 assert_se(f = new(uint32_t, n));
181 TEST_SIZES(f, n);
182
183 /* Finally, let's use some dynamically sized allocations, to make sure this doesn't deteriorate */
184 for (unsigned i = 0; i < 50; i++) {
185 _cleanup_free_ uint64_t *g = NULL;
186 size_t m;
187
188 m = random_u64_range(16*1024);
189 assert_se(g = new(uint64_t, m));
190 TEST_SIZES(g, m);
191 }
192 }
193
194 DEFINE_TEST_MAIN(LOG_DEBUG);
195