1 | /* ---------------------------------------------------------------------------- |
2 | Copyright (c) 2018-2020, Microsoft Research, Daan Leijen |
3 | This is free software; you can redistribute it and/or modify it under the |
4 | terms of the MIT license. A copy of the license can be found in the file |
5 | "LICENSE" at the root of this distribution. |
6 | -----------------------------------------------------------------------------*/ |
7 | #if defined(__GNUC__) && !defined(__clang__) |
8 | #pragma GCC diagnostic ignored "-Walloc-size-larger-than=" |
9 | #endif |
10 | |
11 | /* |
12 | Testing allocators is difficult as bugs may only surface after particular |
13 | allocation patterns. The main approach to testing _mimalloc_ is therefore |
14 | to have extensive internal invariant checking (see `page_is_valid` in `page.c` |
15 | for example), which is enabled in debug mode with `-DMI_DEBUG_FULL=ON`. |
16 | The main testing is then to run `mimalloc-bench` [1] using full invariant checking |
17 | to catch any potential problems over a wide range of intensive allocation bench |
18 | marks. |
19 | |
20 | However, this does not test well for the entire API surface. In this test file |
21 | we therefore test the API over various inputs. Please add more tests :-) |
22 | |
23 | [1] https://github.com/daanx/mimalloc-bench |
24 | */ |
25 | |
26 | #include <assert.h> |
27 | #include <stdbool.h> |
28 | #include <stdint.h> |
29 | #include <errno.h> |
30 | |
31 | #ifdef __cplusplus |
32 | #include <vector> |
33 | #endif |
34 | |
35 | #include "mimalloc.h" |
36 | // #include "mimalloc-internal.h" |
37 | #include "mimalloc-types.h" // for MI_DEBUG |
38 | |
39 | #include "testhelper.h" |
40 | |
41 | // --------------------------------------------------------------------------- |
42 | // Test functions |
43 | // --------------------------------------------------------------------------- |
44 | bool test_heap1(void); |
45 | bool test_heap2(void); |
46 | bool test_stl_allocator1(void); |
47 | bool test_stl_allocator2(void); |
48 | |
49 | // --------------------------------------------------------------------------- |
50 | // Main testing |
51 | // --------------------------------------------------------------------------- |
52 | int main(void) { |
53 | mi_option_disable(mi_option_verbose); |
54 | |
55 | // --------------------------------------------------- |
56 | // Malloc |
57 | // --------------------------------------------------- |
58 | |
59 | CHECK_BODY("malloc-zero" ) { |
60 | void* p = mi_malloc(0); |
61 | result = (p != NULL); |
62 | mi_free(p); |
63 | }; |
64 | CHECK_BODY("malloc-nomem1" ) { |
65 | result = (mi_malloc((size_t)PTRDIFF_MAX + (size_t)1) == NULL); |
66 | }; |
67 | CHECK_BODY("malloc-null" ) { |
68 | mi_free(NULL); |
69 | }; |
70 | CHECK_BODY("calloc-overflow" ) { |
71 | // use (size_t)&mi_calloc to get some number without triggering compiler warnings |
72 | result = (mi_calloc((size_t)&mi_calloc,SIZE_MAX/1000) == NULL); |
73 | }; |
74 | CHECK_BODY("calloc0" ) { |
75 | void* p = mi_calloc(0,1000); |
76 | result = (mi_usable_size(p) <= 16); |
77 | mi_free(p); |
78 | }; |
79 | CHECK_BODY("malloc-large" ) { // see PR #544. |
80 | void* p = mi_malloc(67108872); |
81 | mi_free(p); |
82 | }; |
83 | |
84 | // --------------------------------------------------- |
85 | // Extended |
86 | // --------------------------------------------------- |
87 | CHECK_BODY("posix_memalign1" ) { |
88 | void* p = &p; |
89 | int err = mi_posix_memalign(&p, sizeof(void*), 32); |
90 | result = ((err==0 && (uintptr_t)p % sizeof(void*) == 0) || p==&p); |
91 | mi_free(p); |
92 | }; |
93 | CHECK_BODY("posix_memalign_no_align" ) { |
94 | void* p = &p; |
95 | int err = mi_posix_memalign(&p, 3, 32); |
96 | result = (err==EINVAL && p==&p); |
97 | }; |
98 | CHECK_BODY("posix_memalign_zero" ) { |
99 | void* p = &p; |
100 | int err = mi_posix_memalign(&p, sizeof(void*), 0); |
101 | mi_free(p); |
102 | result = (err==0); |
103 | }; |
104 | CHECK_BODY("posix_memalign_nopow2" ) { |
105 | void* p = &p; |
106 | int err = mi_posix_memalign(&p, 3*sizeof(void*), 32); |
107 | result = (err==EINVAL && p==&p); |
108 | }; |
109 | CHECK_BODY("posix_memalign_nomem" ) { |
110 | void* p = &p; |
111 | int err = mi_posix_memalign(&p, sizeof(void*), SIZE_MAX); |
112 | result = (err==ENOMEM && p==&p); |
113 | }; |
114 | |
115 | // --------------------------------------------------- |
116 | // Aligned API |
117 | // --------------------------------------------------- |
118 | CHECK_BODY("malloc-aligned1" ) { |
119 | void* p = mi_malloc_aligned(32,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p); |
120 | }; |
121 | CHECK_BODY("malloc-aligned2" ) { |
122 | void* p = mi_malloc_aligned(48,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p); |
123 | }; |
124 | CHECK_BODY("malloc-aligned3" ) { |
125 | void* p1 = mi_malloc_aligned(48,32); bool result1 = (p1 != NULL && (uintptr_t)(p1) % 32 == 0); |
126 | void* p2 = mi_malloc_aligned(48,32); bool result2 = (p2 != NULL && (uintptr_t)(p2) % 32 == 0); |
127 | mi_free(p2); |
128 | mi_free(p1); |
129 | result = (result1&&result2); |
130 | }; |
131 | CHECK_BODY("malloc-aligned4" ) { |
132 | void* p; |
133 | bool ok = true; |
134 | for (int i = 0; i < 8 && ok; i++) { |
135 | p = mi_malloc_aligned(8, 16); |
136 | ok = (p != NULL && (uintptr_t)(p) % 16 == 0); mi_free(p); |
137 | } |
138 | result = ok; |
139 | }; |
140 | CHECK_BODY("malloc-aligned5" ) { |
141 | void* p = mi_malloc_aligned(4097,4096); |
142 | size_t usable = mi_usable_size(p); |
143 | result = (usable >= 4097 && usable < 16000); |
144 | printf("malloc_aligned5: usable size: %zi\n" , usable); |
145 | mi_free(p); |
146 | }; |
147 | CHECK_BODY("malloc-aligned6" ) { |
148 | bool ok = true; |
149 | for (size_t align = 1; align <= MI_ALIGNMENT_MAX && ok; align *= 2) { |
150 | void* ps[8]; |
151 | for (int i = 0; i < 8 && ok; i++) { |
152 | ps[i] = mi_malloc_aligned(align*13 /*size*/, align); |
153 | if (ps[i] == NULL || (uintptr_t)(ps[i]) % align != 0) { |
154 | ok = false; |
155 | } |
156 | } |
157 | for (int i = 0; i < 8 && ok; i++) { |
158 | mi_free(ps[i]); |
159 | } |
160 | } |
161 | result = ok; |
162 | }; |
163 | CHECK_BODY("malloc-aligned7" ) { |
164 | void* p = mi_malloc_aligned(1024,MI_ALIGNMENT_MAX); mi_free(p); |
165 | }; |
166 | CHECK_BODY("malloc-aligned8" ) { |
167 | void* p = mi_malloc_aligned(1024,2*MI_ALIGNMENT_MAX); mi_free(p); |
168 | }; |
169 | CHECK_BODY("malloc-aligned-at1" ) { |
170 | void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p); |
171 | }; |
172 | CHECK_BODY("malloc-aligned-at2" ) { |
173 | void* p = mi_malloc_aligned_at(50,32,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 32 == 0); mi_free(p); |
174 | }; |
175 | CHECK_BODY("memalign1" ) { |
176 | void* p; |
177 | bool ok = true; |
178 | for (int i = 0; i < 8 && ok; i++) { |
179 | p = mi_memalign(16,8); |
180 | ok = (p != NULL && (uintptr_t)(p) % 16 == 0); mi_free(p); |
181 | } |
182 | result = ok; |
183 | }; |
184 | |
185 | // --------------------------------------------------- |
186 | // Reallocation |
187 | // --------------------------------------------------- |
188 | CHECK_BODY("realloc-null" ) { |
189 | void* p = mi_realloc(NULL,4); |
190 | result = (p != NULL); |
191 | mi_free(p); |
192 | }; |
193 | |
194 | CHECK_BODY("realloc-null-sizezero" ) { |
195 | void* p = mi_realloc(NULL,0); // <https://en.cppreference.com/w/c/memory/realloc> "If ptr is NULL, the behavior is the same as calling malloc(new_size)." |
196 | result = (p != NULL); |
197 | mi_free(p); |
198 | }; |
199 | |
200 | CHECK_BODY("realloc-sizezero" ) { |
201 | void* p = mi_malloc(4); |
202 | void* q = mi_realloc(p, 0); |
203 | result = (q != NULL); |
204 | mi_free(q); |
205 | }; |
206 | |
207 | CHECK_BODY("reallocarray-null-sizezero" ) { |
208 | void* p = mi_reallocarray(NULL,0,16); // issue #574 |
209 | result = (p != NULL && errno == 0); |
210 | mi_free(p); |
211 | }; |
212 | |
213 | // --------------------------------------------------- |
214 | // Heaps |
215 | // --------------------------------------------------- |
216 | CHECK("heap_destroy" , test_heap1()); |
217 | CHECK("heap_delete" , test_heap2()); |
218 | |
219 | //mi_stats_print(NULL); |
220 | |
221 | // --------------------------------------------------- |
222 | // various |
223 | // --------------------------------------------------- |
224 | CHECK_BODY("realpath" ) { |
225 | char* s = mi_realpath( "." , NULL ); |
226 | // printf("realpath: %s\n",s); |
227 | mi_free(s); |
228 | }; |
229 | |
230 | CHECK("stl_allocator1" , test_stl_allocator1()); |
231 | CHECK("stl_allocator2" , test_stl_allocator2()); |
232 | |
233 | // --------------------------------------------------- |
234 | // Done |
235 | // ---------------------------------------------------[] |
236 | return print_test_summary(); |
237 | } |
238 | |
239 | // --------------------------------------------------- |
240 | // Larger test functions |
241 | // --------------------------------------------------- |
242 | |
243 | bool test_heap1() { |
244 | mi_heap_t* heap = mi_heap_new(); |
245 | int* p1 = mi_heap_malloc_tp(heap,int); |
246 | int* p2 = mi_heap_malloc_tp(heap,int); |
247 | *p1 = *p2 = 43; |
248 | mi_heap_destroy(heap); |
249 | return true; |
250 | } |
251 | |
252 | bool test_heap2() { |
253 | mi_heap_t* heap = mi_heap_new(); |
254 | int* p1 = mi_heap_malloc_tp(heap,int); |
255 | int* p2 = mi_heap_malloc_tp(heap,int); |
256 | mi_heap_delete(heap); |
257 | *p1 = 42; |
258 | mi_free(p1); |
259 | mi_free(p2); |
260 | return true; |
261 | } |
262 | |
263 | bool test_stl_allocator1() { |
264 | #ifdef __cplusplus |
265 | std::vector<int, mi_stl_allocator<int> > vec; |
266 | vec.push_back(1); |
267 | vec.pop_back(); |
268 | return vec.size() == 0; |
269 | #else |
270 | return true; |
271 | #endif |
272 | } |
273 | |
274 | struct some_struct { int i; int j; double z; }; |
275 | |
276 | bool test_stl_allocator2() { |
277 | #ifdef __cplusplus |
278 | std::vector<some_struct, mi_stl_allocator<some_struct> > vec; |
279 | vec.push_back(some_struct()); |
280 | vec.pop_back(); |
281 | return vec.size() == 0; |
282 | #else |
283 | return true; |
284 | #endif |
285 | } |
286 | |