smallocx.c revision 1.1.1.2 1 1.1 christos #include "test/jemalloc_test.h"
2 1.1 christos #include "jemalloc/jemalloc_macros.h"
3 1.1 christos
4 1.1 christos #define STR_HELPER(x) #x
5 1.1 christos #define STR(x) STR_HELPER(x)
6 1.1 christos
7 1.1 christos #ifndef JEMALLOC_VERSION_GID_IDENT
8 1.1.1.2 christos # error "JEMALLOC_VERSION_GID_IDENT not defined"
9 1.1 christos #endif
10 1.1 christos
11 1.1.1.2 christos #define JOIN(x, y) x##y
12 1.1 christos #define JOIN2(x, y) JOIN(x, y)
13 1.1 christos #define smallocx JOIN2(smallocx_, JEMALLOC_VERSION_GID_IDENT)
14 1.1 christos
15 1.1 christos typedef struct {
16 1.1.1.2 christos void *ptr;
17 1.1 christos size_t size;
18 1.1 christos } smallocx_return_t;
19 1.1 christos
20 1.1.1.2 christos extern smallocx_return_t smallocx(size_t size, int flags);
21 1.1 christos
22 1.1 christos static unsigned
23 1.1 christos get_nsizes_impl(const char *cmd) {
24 1.1 christos unsigned ret;
25 1.1.1.2 christos size_t z;
26 1.1 christos
27 1.1 christos z = sizeof(unsigned);
28 1.1 christos expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
29 1.1 christos "Unexpected mallctl(\"%s\", ...) failure", cmd);
30 1.1 christos
31 1.1 christos return ret;
32 1.1 christos }
33 1.1 christos
34 1.1 christos static unsigned
35 1.1 christos get_nlarge(void) {
36 1.1 christos return get_nsizes_impl("arenas.nlextents");
37 1.1 christos }
38 1.1 christos
39 1.1 christos static size_t
40 1.1 christos get_size_impl(const char *cmd, size_t ind) {
41 1.1 christos size_t ret;
42 1.1 christos size_t z;
43 1.1 christos size_t mib[4];
44 1.1 christos size_t miblen = 4;
45 1.1 christos
46 1.1 christos z = sizeof(size_t);
47 1.1.1.2 christos expect_d_eq(mallctlnametomib(cmd, mib, &miblen), 0,
48 1.1.1.2 christos "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
49 1.1 christos mib[2] = ind;
50 1.1 christos z = sizeof(size_t);
51 1.1.1.2 christos expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0,
52 1.1.1.2 christos "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
53 1.1 christos
54 1.1 christos return ret;
55 1.1 christos }
56 1.1 christos
57 1.1 christos static size_t
58 1.1 christos get_large_size(size_t ind) {
59 1.1 christos return get_size_impl("arenas.lextent.0.size", ind);
60 1.1 christos }
61 1.1 christos
62 1.1 christos /*
63 1.1 christos * On systems which can't merge extents, tests that call this function generate
64 1.1 christos * a lot of dirty memory very quickly. Purging between cycles mitigates
65 1.1 christos * potential OOM on e.g. 32-bit Windows.
66 1.1 christos */
67 1.1 christos static void
68 1.1 christos purge(void) {
69 1.1 christos expect_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
70 1.1 christos "Unexpected mallctl error");
71 1.1 christos }
72 1.1 christos
73 1.1 christos /*
74 1.1 christos * GCC "-Walloc-size-larger-than" warning detects when one of the memory
75 1.1 christos * allocation functions is called with a size larger than the maximum size that
76 1.1 christos * they support. Here we want to explicitly test that the allocation functions
77 1.1 christos * do indeed fail properly when this is the case, which triggers the warning.
78 1.1 christos * Therefore we disable the warning for these tests.
79 1.1 christos */
80 1.1 christos JEMALLOC_DIAGNOSTIC_PUSH
81 1.1 christos JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
82 1.1 christos
83 1.1 christos TEST_BEGIN(test_overflow) {
84 1.1 christos size_t largemax;
85 1.1 christos
86 1.1.1.2 christos largemax = get_large_size(get_nlarge() - 1);
87 1.1 christos
88 1.1.1.2 christos expect_ptr_null(smallocx(largemax + 1, 0).ptr,
89 1.1.1.2 christos "Expected OOM for smallocx(size=%#zx, 0)", largemax + 1);
90 1.1 christos
91 1.1.1.2 christos expect_ptr_null(smallocx(ZU(PTRDIFF_MAX) + 1, 0).ptr,
92 1.1.1.2 christos "Expected OOM for smallocx(size=%#zx, 0)", ZU(PTRDIFF_MAX) + 1);
93 1.1 christos
94 1.1 christos expect_ptr_null(smallocx(SIZE_T_MAX, 0).ptr,
95 1.1 christos "Expected OOM for smallocx(size=%#zx, 0)", SIZE_T_MAX);
96 1.1 christos
97 1.1.1.2 christos expect_ptr_null(smallocx(1, MALLOCX_ALIGN(ZU(PTRDIFF_MAX) + 1)).ptr,
98 1.1 christos "Expected OOM for smallocx(size=1, MALLOCX_ALIGN(%#zx))",
99 1.1.1.2 christos ZU(PTRDIFF_MAX) + 1);
100 1.1 christos }
101 1.1 christos TEST_END
102 1.1 christos
103 1.1 christos static void *
104 1.1 christos remote_alloc(void *arg) {
105 1.1 christos unsigned arena;
106 1.1.1.2 christos size_t sz = sizeof(unsigned);
107 1.1 christos expect_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
108 1.1 christos "Unexpected mallctl() failure");
109 1.1 christos size_t large_sz;
110 1.1 christos sz = sizeof(size_t);
111 1.1.1.2 christos expect_d_eq(
112 1.1.1.2 christos mallctl("arenas.lextent.0.size", (void *)&large_sz, &sz, NULL, 0),
113 1.1.1.2 christos 0, "Unexpected mallctl failure");
114 1.1 christos
115 1.1.1.2 christos smallocx_return_t r = smallocx(
116 1.1.1.2 christos large_sz, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
117 1.1 christos void *ptr = r.ptr;
118 1.1 christos expect_zu_eq(r.size,
119 1.1 christos nallocx(large_sz, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE),
120 1.1 christos "Expected smalloc(size,flags).size == nallocx(size,flags)");
121 1.1 christos void **ret = (void **)arg;
122 1.1 christos *ret = ptr;
123 1.1 christos
124 1.1 christos return NULL;
125 1.1 christos }
126 1.1 christos
127 1.1 christos TEST_BEGIN(test_remote_free) {
128 1.1 christos thd_t thd;
129 1.1 christos void *ret;
130 1.1 christos thd_create(&thd, remote_alloc, (void *)&ret);
131 1.1 christos thd_join(thd, NULL);
132 1.1 christos expect_ptr_not_null(ret, "Unexpected smallocx failure");
133 1.1 christos
134 1.1 christos /* Avoid TCACHE_NONE to explicitly test tcache_flush(). */
135 1.1 christos dallocx(ret, 0);
136 1.1 christos mallctl("thread.tcache.flush", NULL, NULL, NULL, 0);
137 1.1 christos }
138 1.1 christos TEST_END
139 1.1 christos
140 1.1 christos TEST_BEGIN(test_oom) {
141 1.1.1.2 christos size_t largemax;
142 1.1.1.2 christos bool oom;
143 1.1.1.2 christos void *ptrs[3];
144 1.1 christos unsigned i;
145 1.1 christos
146 1.1 christos /*
147 1.1 christos * It should be impossible to allocate three objects that each consume
148 1.1 christos * nearly half the virtual address space.
149 1.1 christos */
150 1.1.1.2 christos largemax = get_large_size(get_nlarge() - 1);
151 1.1 christos oom = false;
152 1.1 christos for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
153 1.1 christos ptrs[i] = smallocx(largemax, 0).ptr;
154 1.1 christos if (ptrs[i] == NULL) {
155 1.1 christos oom = true;
156 1.1 christos }
157 1.1 christos }
158 1.1 christos expect_true(oom,
159 1.1 christos "Expected OOM during series of calls to smallocx(size=%zu, 0)",
160 1.1 christos largemax);
161 1.1 christos for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
162 1.1 christos if (ptrs[i] != NULL) {
163 1.1 christos dallocx(ptrs[i], 0);
164 1.1 christos }
165 1.1 christos }
166 1.1 christos purge();
167 1.1 christos
168 1.1 christos #if LG_SIZEOF_PTR == 3
169 1.1 christos expect_ptr_null(smallocx(0x8000000000000000ULL,
170 1.1.1.2 christos MALLOCX_ALIGN(0x8000000000000000ULL))
171 1.1.1.2 christos .ptr,
172 1.1 christos "Expected OOM for smallocx()");
173 1.1.1.2 christos expect_ptr_null(
174 1.1.1.2 christos smallocx(0x8000000000000000ULL, MALLOCX_ALIGN(0x80000000)).ptr,
175 1.1 christos "Expected OOM for smallocx()");
176 1.1 christos #else
177 1.1 christos expect_ptr_null(smallocx(0x80000000UL, MALLOCX_ALIGN(0x80000000UL)).ptr,
178 1.1 christos "Expected OOM for smallocx()");
179 1.1 christos #endif
180 1.1 christos }
181 1.1 christos TEST_END
182 1.1 christos
183 1.1 christos /* Re-enable the "-Walloc-size-larger-than=" warning */
184 1.1 christos JEMALLOC_DIAGNOSTIC_POP
185 1.1 christos
186 1.1 christos TEST_BEGIN(test_basic) {
187 1.1 christos #define MAXSZ (((size_t)1) << 23)
188 1.1 christos size_t sz;
189 1.1 christos
190 1.1 christos for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) {
191 1.1 christos smallocx_return_t ret;
192 1.1.1.2 christos size_t nsz, rsz, smz;
193 1.1.1.2 christos void *p;
194 1.1 christos nsz = nallocx(sz, 0);
195 1.1 christos expect_zu_ne(nsz, 0, "Unexpected nallocx() error");
196 1.1 christos ret = smallocx(sz, 0);
197 1.1 christos p = ret.ptr;
198 1.1 christos smz = ret.size;
199 1.1.1.2 christos expect_ptr_not_null(
200 1.1.1.2 christos p, "Unexpected smallocx(size=%zx, flags=0) error", sz);
201 1.1 christos rsz = sallocx(p, 0);
202 1.1 christos expect_zu_ge(rsz, sz, "Real size smaller than expected");
203 1.1 christos expect_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch");
204 1.1 christos expect_zu_eq(nsz, smz, "nallocx()/smallocx() size mismatch");
205 1.1 christos dallocx(p, 0);
206 1.1 christos
207 1.1 christos ret = smallocx(sz, 0);
208 1.1 christos p = ret.ptr;
209 1.1 christos smz = ret.size;
210 1.1.1.2 christos expect_ptr_not_null(
211 1.1.1.2 christos p, "Unexpected smallocx(size=%zx, flags=0) error", sz);
212 1.1 christos dallocx(p, 0);
213 1.1 christos
214 1.1 christos nsz = nallocx(sz, MALLOCX_ZERO);
215 1.1 christos expect_zu_ne(nsz, 0, "Unexpected nallocx() error");
216 1.1 christos expect_zu_ne(smz, 0, "Unexpected smallocx() error");
217 1.1 christos ret = smallocx(sz, MALLOCX_ZERO);
218 1.1 christos p = ret.ptr;
219 1.1 christos expect_ptr_not_null(p,
220 1.1 christos "Unexpected smallocx(size=%zx, flags=MALLOCX_ZERO) error",
221 1.1 christos nsz);
222 1.1 christos rsz = sallocx(p, 0);
223 1.1 christos expect_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch");
224 1.1 christos expect_zu_eq(nsz, smz, "nallocx()/smallocx() size mismatch");
225 1.1 christos dallocx(p, 0);
226 1.1 christos purge();
227 1.1 christos }
228 1.1 christos #undef MAXSZ
229 1.1 christos }
230 1.1 christos TEST_END
231 1.1 christos
232 1.1 christos TEST_BEGIN(test_alignment_and_size) {
233 1.1 christos const char *percpu_arena;
234 1.1.1.2 christos size_t sz = sizeof(percpu_arena);
235 1.1 christos
236 1.1.1.2 christos if (mallctl("opt.percpu_arena", (void *)&percpu_arena, &sz, NULL, 0)
237 1.1.1.2 christos || strcmp(percpu_arena, "disabled") != 0) {
238 1.1.1.2 christos test_skip(
239 1.1.1.2 christos "test_alignment_and_size skipped: "
240 1.1 christos "not working with percpu arena.");
241 1.1 christos };
242 1.1 christos #define MAXALIGN (((size_t)1) << 23)
243 1.1 christos #define NITER 4
244 1.1.1.2 christos size_t nsz, rsz, smz, alignment, total;
245 1.1 christos unsigned i;
246 1.1.1.2 christos void *ps[NITER];
247 1.1 christos
248 1.1 christos for (i = 0; i < NITER; i++) {
249 1.1 christos ps[i] = NULL;
250 1.1 christos }
251 1.1 christos
252 1.1.1.2 christos for (alignment = 8; alignment <= MAXALIGN; alignment <<= 1) {
253 1.1 christos total = 0;
254 1.1.1.2 christos for (sz = 1; sz < 3 * alignment && sz < (1U << 31);
255 1.1.1.2 christos sz += (alignment >> (LG_SIZEOF_PTR - 1)) - 1) {
256 1.1 christos for (i = 0; i < NITER; i++) {
257 1.1.1.2 christos nsz = nallocx(sz,
258 1.1.1.2 christos MALLOCX_ALIGN(alignment) | MALLOCX_ZERO);
259 1.1 christos expect_zu_ne(nsz, 0,
260 1.1 christos "nallocx() error for alignment=%zu, "
261 1.1.1.2 christos "size=%zu (%#zx)",
262 1.1.1.2 christos alignment, sz, sz);
263 1.1.1.2 christos smallocx_return_t ret = smallocx(sz,
264 1.1.1.2 christos MALLOCX_ALIGN(alignment) | MALLOCX_ZERO);
265 1.1 christos ps[i] = ret.ptr;
266 1.1 christos expect_ptr_not_null(ps[i],
267 1.1 christos "smallocx() error for alignment=%zu, "
268 1.1.1.2 christos "size=%zu (%#zx)",
269 1.1.1.2 christos alignment, sz, sz);
270 1.1 christos rsz = sallocx(ps[i], 0);
271 1.1 christos smz = ret.size;
272 1.1 christos expect_zu_ge(rsz, sz,
273 1.1 christos "Real size smaller than expected for "
274 1.1.1.2 christos "alignment=%zu, size=%zu",
275 1.1.1.2 christos alignment, sz);
276 1.1 christos expect_zu_eq(nsz, rsz,
277 1.1 christos "nallocx()/sallocx() size mismatch for "
278 1.1.1.2 christos "alignment=%zu, size=%zu",
279 1.1.1.2 christos alignment, sz);
280 1.1 christos expect_zu_eq(nsz, smz,
281 1.1 christos "nallocx()/smallocx() size mismatch for "
282 1.1.1.2 christos "alignment=%zu, size=%zu",
283 1.1 christos alignment, sz);
284 1.1.1.2 christos expect_ptr_null((void *)((uintptr_t)ps[i]
285 1.1.1.2 christos & (alignment - 1)),
286 1.1.1.2 christos "%p inadequately aligned for"
287 1.1.1.2 christos " alignment=%zu, size=%zu",
288 1.1.1.2 christos ps[i], alignment, sz);
289 1.1 christos total += rsz;
290 1.1 christos if (total >= (MAXALIGN << 1)) {
291 1.1 christos break;
292 1.1 christos }
293 1.1 christos }
294 1.1 christos for (i = 0; i < NITER; i++) {
295 1.1 christos if (ps[i] != NULL) {
296 1.1 christos dallocx(ps[i], 0);
297 1.1 christos ps[i] = NULL;
298 1.1 christos }
299 1.1 christos }
300 1.1 christos }
301 1.1 christos purge();
302 1.1 christos }
303 1.1 christos #undef MAXALIGN
304 1.1 christos #undef NITER
305 1.1 christos }
306 1.1 christos TEST_END
307 1.1 christos
308 1.1 christos int
309 1.1 christos main(void) {
310 1.1.1.2 christos return test(test_overflow, test_oom, test_remote_free, test_basic,
311 1.1 christos test_alignment_and_size);
312 1.1 christos }
313