1 #include "test/jemalloc_test.h"
2 
3 static unsigned
get_nsizes_impl(const char * cmd)4 get_nsizes_impl(const char *cmd) {
5 	unsigned ret;
6 	size_t z;
7 
8 	z = sizeof(unsigned);
9 	assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
10 	    "Unexpected mallctl(\"%s\", ...) failure", cmd);
11 
12 	return ret;
13 }
14 
15 static unsigned
get_nlarge(void)16 get_nlarge(void) {
17 	return get_nsizes_impl("arenas.nlextents");
18 }
19 
20 static size_t
get_size_impl(const char * cmd,size_t ind)21 get_size_impl(const char *cmd, size_t ind) {
22 	size_t ret;
23 	size_t z;
24 	size_t mib[4];
25 	size_t miblen = 4;
26 
27 	z = sizeof(size_t);
28 	assert_d_eq(mallctlnametomib(cmd, mib, &miblen),
29 	    0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
30 	mib[2] = ind;
31 	z = sizeof(size_t);
32 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
33 	    0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
34 
35 	return ret;
36 }
37 
38 static size_t
get_large_size(size_t ind)39 get_large_size(size_t ind) {
40 	return get_size_impl("arenas.lextent.0.size", ind);
41 }
42 
43 /*
44  * On systems which can't merge extents, tests that call this function generate
45  * a lot of dirty memory very quickly.  Purging between cycles mitigates
46  * potential OOM on e.g. 32-bit Windows.
47  */
48 static void
purge(void)49 purge(void) {
50 	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
51 	    "Unexpected mallctl error");
52 }
53 
TEST_BEGIN(test_overflow)54 TEST_BEGIN(test_overflow) {
55 	size_t largemax;
56 
57 	largemax = get_large_size(get_nlarge()-1);
58 
59 	assert_ptr_null(mallocx(largemax+1, 0),
60 	    "Expected OOM for mallocx(size=%#zx, 0)", largemax+1);
61 
62 	assert_ptr_null(mallocx(ZU(PTRDIFF_MAX)+1, 0),
63 	    "Expected OOM for mallocx(size=%#zx, 0)", ZU(PTRDIFF_MAX)+1);
64 
65 	assert_ptr_null(mallocx(SIZE_T_MAX, 0),
66 	    "Expected OOM for mallocx(size=%#zx, 0)", SIZE_T_MAX);
67 
68 	assert_ptr_null(mallocx(1, MALLOCX_ALIGN(ZU(PTRDIFF_MAX)+1)),
69 	    "Expected OOM for mallocx(size=1, MALLOCX_ALIGN(%#zx))",
70 	    ZU(PTRDIFF_MAX)+1);
71 }
72 TEST_END
73 
TEST_BEGIN(test_oom)74 TEST_BEGIN(test_oom) {
75 	size_t largemax;
76 	bool oom;
77 	void *ptrs[3];
78 	unsigned i;
79 
80 	/*
81 	 * It should be impossible to allocate three objects that each consume
82 	 * nearly half the virtual address space.
83 	 */
84 	largemax = get_large_size(get_nlarge()-1);
85 	oom = false;
86 	for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
87 		ptrs[i] = mallocx(largemax, 0);
88 		if (ptrs[i] == NULL) {
89 			oom = true;
90 		}
91 	}
92 	assert_true(oom,
93 	    "Expected OOM during series of calls to mallocx(size=%zu, 0)",
94 	    largemax);
95 	for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
96 		if (ptrs[i] != NULL) {
97 			dallocx(ptrs[i], 0);
98 		}
99 	}
100 	purge();
101 
102 #if LG_SIZEOF_PTR == 3
103 	assert_ptr_null(mallocx(0x8000000000000000ULL,
104 	    MALLOCX_ALIGN(0x8000000000000000ULL)),
105 	    "Expected OOM for mallocx()");
106 	assert_ptr_null(mallocx(0x8000000000000000ULL,
107 	    MALLOCX_ALIGN(0x80000000)),
108 	    "Expected OOM for mallocx()");
109 #else
110 	assert_ptr_null(mallocx(0x80000000UL, MALLOCX_ALIGN(0x80000000UL)),
111 	    "Expected OOM for mallocx()");
112 #endif
113 }
114 TEST_END
115 
TEST_BEGIN(test_basic)116 TEST_BEGIN(test_basic) {
117 #define MAXSZ (((size_t)1) << 23)
118 	size_t sz;
119 
120 	for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) {
121 		size_t nsz, rsz;
122 		void *p;
123 		nsz = nallocx(sz, 0);
124 		assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
125 		p = mallocx(sz, 0);
126 		assert_ptr_not_null(p,
127 		    "Unexpected mallocx(size=%zx, flags=0) error", sz);
128 		rsz = sallocx(p, 0);
129 		assert_zu_ge(rsz, sz, "Real size smaller than expected");
130 		assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch");
131 		dallocx(p, 0);
132 
133 		p = mallocx(sz, 0);
134 		assert_ptr_not_null(p,
135 		    "Unexpected mallocx(size=%zx, flags=0) error", sz);
136 		dallocx(p, 0);
137 
138 		nsz = nallocx(sz, MALLOCX_ZERO);
139 		assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
140 		p = mallocx(sz, MALLOCX_ZERO);
141 		assert_ptr_not_null(p,
142 		    "Unexpected mallocx(size=%zx, flags=MALLOCX_ZERO) error",
143 		    nsz);
144 		rsz = sallocx(p, 0);
145 		assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch");
146 		dallocx(p, 0);
147 		purge();
148 	}
149 #undef MAXSZ
150 }
151 TEST_END
152 
TEST_BEGIN(test_alignment_and_size)153 TEST_BEGIN(test_alignment_and_size) {
154 	const char *percpu_arena;
155 	size_t sz = sizeof(percpu_arena);
156 
157 	if(mallctl("opt.percpu_arena", (void *)&percpu_arena, &sz, NULL, 0) ||
158 	    strcmp(percpu_arena, "disabled") != 0) {
159 		test_skip("test_alignment_and_size skipped: "
160 		    "not working with percpu arena.");
161 	};
162 #define MAXALIGN (((size_t)1) << 23)
163 #define NITER 4
164 	size_t nsz, rsz, alignment, total;
165 	unsigned i;
166 	void *ps[NITER];
167 
168 	for (i = 0; i < NITER; i++) {
169 		ps[i] = NULL;
170 	}
171 
172 	for (alignment = 8;
173 	    alignment <= MAXALIGN;
174 	    alignment <<= 1) {
175 		total = 0;
176 		for (sz = 1;
177 		    sz < 3 * alignment && sz < (1U << 31);
178 		    sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
179 			for (i = 0; i < NITER; i++) {
180 				nsz = nallocx(sz, MALLOCX_ALIGN(alignment) |
181 				    MALLOCX_ZERO);
182 				assert_zu_ne(nsz, 0,
183 				    "nallocx() error for alignment=%zu, "
184 				    "size=%zu (%#zx)", alignment, sz, sz);
185 				ps[i] = mallocx(sz, MALLOCX_ALIGN(alignment) |
186 				    MALLOCX_ZERO);
187 				assert_ptr_not_null(ps[i],
188 				    "mallocx() error for alignment=%zu, "
189 				    "size=%zu (%#zx)", alignment, sz, sz);
190 				rsz = sallocx(ps[i], 0);
191 				assert_zu_ge(rsz, sz,
192 				    "Real size smaller than expected for "
193 				    "alignment=%zu, size=%zu", alignment, sz);
194 				assert_zu_eq(nsz, rsz,
195 				    "nallocx()/sallocx() size mismatch for "
196 				    "alignment=%zu, size=%zu", alignment, sz);
197 				assert_ptr_null(
198 				    (void *)((uintptr_t)ps[i] & (alignment-1)),
199 				    "%p inadequately aligned for"
200 				    " alignment=%zu, size=%zu", ps[i],
201 				    alignment, sz);
202 				total += rsz;
203 				if (total >= (MAXALIGN << 1)) {
204 					break;
205 				}
206 			}
207 			for (i = 0; i < NITER; i++) {
208 				if (ps[i] != NULL) {
209 					dallocx(ps[i], 0);
210 					ps[i] = NULL;
211 				}
212 			}
213 		}
214 		purge();
215 	}
216 #undef MAXALIGN
217 #undef NITER
218 }
219 TEST_END
220 
221 int
main(void)222 main(void) {
223 	return test(
224 	    test_overflow,
225 	    test_oom,
226 	    test_basic,
227 	    test_alignment_and_size);
228 }
229