1 /*
2  * Unit test suite for memory functions
3  *
4  * Copyright 2003 Dimitrie O. Paun
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdlib.h>
22 #include <malloc.h>
23 #include <errno.h>
24 #include "wine/test.h"
25 
26 static void (__cdecl *p_aligned_free)(void*) = NULL;
27 static void * (__cdecl *p_aligned_malloc)(size_t,size_t) = NULL;
28 static void * (__cdecl *p_aligned_offset_malloc)(size_t,size_t,size_t) = NULL;
29 static void * (__cdecl *p_aligned_realloc)(void*,size_t,size_t) = NULL;
30 static void * (__cdecl *p_aligned_offset_realloc)(void*,size_t,size_t,size_t) = NULL;
31 
32 static void test_aligned_malloc(unsigned int size, unsigned int alignment)
33 {
34     void *mem;
35 
36     mem = p_aligned_malloc(size, alignment);
37 
38     if ((alignment & (alignment - 1)) == 0)
39         ok(mem != NULL, "_aligned_malloc(%d, %d) failed\n", size, alignment);
40     else
41         ok(mem == NULL, "_aligned_malloc(%d, %d) should have failed\n", size, alignment);
42 
43     if (mem)
44     {
45         ok(((DWORD_PTR)mem & (alignment ? alignment - 1 : 0)) == 0,
46            "_aligned_malloc(%d, %d) not aligned: %p\n", size, alignment, mem);
47         if (winetest_debug > 1)
48         {
49             void *saved;
50             saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1));
51             trace("_aligned_malloc(%3d, %3d) returns %p, saved = %p\n", size, alignment, mem, saved );
52         }
53         p_aligned_free(mem);
54     }
55     else
56         ok(errno == EINVAL, "_aligned_malloc(%d, %d) errno: %d != %d\n", size, alignment, errno, EINVAL);
57 }
58 
59 static void test_aligned_offset_malloc(unsigned int size, unsigned int alignment, unsigned int offset)
60 {
61     void *mem;
62 
63     mem = p_aligned_offset_malloc(size, alignment, offset);
64 
65     if ((alignment & (alignment - 1)) == 0)
66         if (offset < size)
67             ok(mem != NULL, "_aligned_offset_malloc(%d, %d, %d) failed\n", size, alignment, offset);
68         else
69             ok(errno == EINVAL, "_aligned_offset_malloc(%d, %d, %d) errno: %d != %d\n", size, alignment, offset, errno, EINVAL);
70     else
71         ok(mem == NULL, "_aligned_offset_malloc(%d, %d, %d) should have failed\n", size, alignment, offset);
72 
73     if (mem)
74     {
75         ok(((DWORD_PTR)((char *)mem + offset) & (alignment ? alignment - 1 : 0)) == 0,
76            "_aligned_offset_malloc(%d, %d, %d) not aligned: %p\n", size, alignment, offset, mem);
77         if (winetest_debug > 1)
78         {
79             void *saved;
80             saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1));
81             trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p\n",
82                   size, alignment, offset, mem, saved);
83         }
84         p_aligned_free(mem);
85     }
86     else
87         ok(errno == EINVAL, "_aligned_offset_malloc(%d, %d, %d) errno: %d != %d\n", size, alignment, offset, errno, EINVAL);
88 }
89 
90 static void test_aligned_realloc(unsigned int size1, unsigned int size2, unsigned int alignment)
91 {
92     void *mem, *mem1, *mem2;
93 
94     mem = p_aligned_malloc(size1, alignment);
95 
96     if ((alignment & (alignment - 1)) == 0)
97         ok(mem != NULL, "_aligned_malloc(%d, %d) failed\n", size1, alignment);
98     else
99         ok(mem == NULL, "_aligned_malloc(%d, %d) should have failed\n", size1, alignment);
100 
101     if (mem)
102     {
103 	mem1 = malloc(size1);
104         if (mem1)
105         {
106             unsigned int i;
107             for (i = 0; i < size1; i++)
108                 ((char *)mem)[i] = i + 1;
109             memcpy(mem1, mem, size1);
110         }
111 
112         ok(((DWORD_PTR)mem & (alignment ? alignment - 1 : 0)) == 0,
113            "_aligned_malloc(%d, %d) not aligned: %p\n", size1, alignment, mem);
114         if (winetest_debug > 1)
115         {
116             void *saved;
117             saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1));
118             trace("_aligned_malloc(%3d, %3d) returns %p, saved = %p\n", size1, alignment, mem, saved);
119         }
120 
121         mem2 = p_aligned_realloc(mem, size2, alignment);
122 
123         ok(mem2 != NULL, "_aligned_realloc(%p, %d, %d) failed\n", mem, size2, alignment);
124 
125         if (mem2)
126         {
127             ok(((DWORD_PTR)mem2 & (alignment ? alignment - 1 : 0)) == 0,
128                "_aligned_realloc(%p, %d, %d) not aligned: %p\n", mem, size2, alignment, mem2);
129             if (winetest_debug > 1)
130             {
131                 void *saved;
132                 saved = *(void **)((DWORD_PTR)((char *)mem2 - sizeof(void *)) & ~(sizeof(void *) - 1));
133                 trace("_aligned_realloc(%p, %3d, %3d) returns %p, saved = %p\n",
134                       mem, size2, alignment, mem2, saved);
135             }
136             if (mem1)
137             {
138                 ok(memcmp(mem2, mem1, min(size1, size2))==0, "_aligned_realloc(%p, %d, %d) has different data\n", mem, size2, alignment);
139                 if (memcmp(mem2, mem1, min(size1, size2)) && winetest_debug > 1)
140                 {
141                     unsigned int i;
142                     for (i = 0; i < min(size1, size2); i++)
143                     {
144                         if (((char *)mem2)[i] != ((char *)mem1)[i])
145                             trace("%d: %02x != %02x\n", i, ((char *)mem2)[i] & 0xff, ((char *)mem1)[i] & 0xff);
146                     }
147                 }
148             }
149             p_aligned_free(mem2);
150         } else {
151             ok(errno == EINVAL, "_aligned_realloc(%p, %d, %d) errno: %d != %d\n", mem, size2, alignment, errno, EINVAL);
152             p_aligned_free(mem);
153         }
154 
155         free(mem1);
156     }
157     else
158         ok(errno == EINVAL, "_aligned_malloc(%d, %d) errno: %d != %d\n", size1, alignment, errno, EINVAL);
159 }
160 
161 static void test_aligned_offset_realloc(unsigned int size1, unsigned int size2,
162                                         unsigned int alignment, unsigned int offset)
163 {
164     void *mem, *mem1, *mem2;
165 
166     mem = p_aligned_offset_malloc(size1, alignment, offset);
167 
168     if ((alignment & (alignment - 1)) == 0)
169         ok(mem != NULL, "_aligned_offset_malloc(%d, %d, %d) failed\n", size1, alignment, offset);
170     else
171         ok(mem == NULL, "_aligned_offset_malloc(%d, %d, %d) should have failed\n", size1, alignment, offset);
172 
173     if (mem)
174     {
175 	mem1 = malloc(size1);
176         if (mem1)
177         {
178             unsigned int i;
179             for (i = 0; i < size1; i++)
180                 ((char *)mem)[i] = i + 1;
181             memcpy(mem1, mem, size1);
182         }
183 
184         ok(((DWORD_PTR)((char *)mem + offset) & (alignment ? alignment - 1 : 0)) == 0,
185            "_aligned_offset_malloc(%d, %d, %d) not aligned: %p\n", size1, alignment, offset, mem);
186         if (winetest_debug > 1)
187         {
188             void *saved;
189             saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1));
190             trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p\n",
191                   size1, alignment, offset, mem, saved);
192         }
193 
194         mem2 = p_aligned_offset_realloc(mem, size2, alignment, offset);
195 
196         ok(mem2 != NULL, "_aligned_offset_realloc(%p, %d, %d, %d) failed\n", mem, size2, alignment, offset);
197 
198         if (mem2)
199         {
200             ok(((DWORD_PTR)((char *)mem + offset) & (alignment ? alignment - 1 : 0)) == 0,
201                "_aligned_offset_realloc(%p, %d, %d, %d) not aligned: %p\n", mem, size2, alignment, offset, mem2);
202             if (winetest_debug > 1)
203             {
204                 void *saved;
205                 saved = *(void **)((DWORD_PTR)((char *)mem2 - sizeof(void *)) & ~(sizeof(void *) - 1));
206                 trace("_aligned_offset_realloc(%p, %3d, %3d, %3d) returns %p, saved = %p\n",
207                       mem, size2, alignment, offset, mem2, saved);
208             }
209             if (mem1)
210             {
211                 ok(memcmp(mem2, mem1, min(size1, size2))==0, "_aligned_offset_realloc(%p, %d, %d, %d) has different data\n", mem, size2, alignment, offset);
212                 if (memcmp(mem2, mem1, min(size1, size2)) && winetest_debug > 1)
213                 {
214                     unsigned int i;
215                     for (i = 0; i < min(size1, size2); i++)
216                     {
217                         if (((char *)mem2)[i] != ((char *)mem1)[i])
218                             trace("%d: %02x != %02x\n", i, ((char *)mem2)[i] & 0xff, ((char *)mem1)[i] & 0xff);
219                     }
220                 }
221             }
222             p_aligned_free(mem2);
223         } else {
224             ok(errno == EINVAL, "_aligned_offset_realloc(%p, %d, %d, %d) errno: %d != %d\n", mem, size2, alignment, offset, errno, EINVAL);
225             p_aligned_free(mem);
226         }
227 
228         free(mem1);
229     }
230     else
231         ok(errno == EINVAL, "_aligned_offset_malloc(%d, %d) errno: %d != %d\n", size1, alignment, errno, EINVAL);
232 }
233 
234 static void test_aligned(void)
235 {
236     HMODULE msvcrt = GetModuleHandleA("msvcrt.dll");
237 
238     if (msvcrt == NULL)
239         return;
240 
241     p_aligned_free = (void*)GetProcAddress(msvcrt, "_aligned_free");
242     p_aligned_malloc = (void*)GetProcAddress(msvcrt, "_aligned_malloc");
243     p_aligned_offset_malloc = (void*)GetProcAddress(msvcrt, "_aligned_offset_malloc");
244     p_aligned_realloc = (void*)GetProcAddress(msvcrt, "_aligned_realloc");
245     p_aligned_offset_realloc = (void*)GetProcAddress(msvcrt, "_aligned_offset_realloc");
246 
247     if (!p_aligned_free || !p_aligned_malloc || !p_aligned_offset_malloc || !p_aligned_realloc || !p_aligned_offset_realloc)
248     {
249         skip("aligned memory tests skipped\n");
250         return;
251     }
252 
253     test_aligned_malloc(256, 0);
254     test_aligned_malloc(256, 1);
255     test_aligned_malloc(256, 2);
256     test_aligned_malloc(256, 3);
257     test_aligned_malloc(256, 4);
258     test_aligned_malloc(256, 8);
259     test_aligned_malloc(256, 16);
260     test_aligned_malloc(256, 32);
261     test_aligned_malloc(256, 64);
262     test_aligned_malloc(256, 127);
263     test_aligned_malloc(256, 128);
264 
265     test_aligned_offset_malloc(256, 0, 0);
266     test_aligned_offset_malloc(256, 1, 0);
267     test_aligned_offset_malloc(256, 2, 0);
268     test_aligned_offset_malloc(256, 3, 0);
269     test_aligned_offset_malloc(256, 4, 0);
270     test_aligned_offset_malloc(256, 8, 0);
271     test_aligned_offset_malloc(256, 16, 0);
272     test_aligned_offset_malloc(256, 32, 0);
273     test_aligned_offset_malloc(256, 64, 0);
274     test_aligned_offset_malloc(256, 127, 0);
275     test_aligned_offset_malloc(256, 128, 0);
276 
277     test_aligned_offset_malloc(256, 0, 4);
278     test_aligned_offset_malloc(256, 1, 4);
279     test_aligned_offset_malloc(256, 2, 4);
280     test_aligned_offset_malloc(256, 3, 4);
281     test_aligned_offset_malloc(256, 4, 4);
282     test_aligned_offset_malloc(256, 8, 4);
283     test_aligned_offset_malloc(256, 16, 4);
284     test_aligned_offset_malloc(256, 32, 4);
285     test_aligned_offset_malloc(256, 64, 4);
286     test_aligned_offset_malloc(256, 127, 4);
287     test_aligned_offset_malloc(256, 128, 4);
288 
289     test_aligned_offset_malloc(256, 8, 7);
290     test_aligned_offset_malloc(256, 8, 9);
291     test_aligned_offset_malloc(256, 8, 16);
292     test_aligned_offset_malloc(256, 8, 17);
293     test_aligned_offset_malloc(256, 8, 254);
294     test_aligned_offset_malloc(256, 8, 255);
295     test_aligned_offset_malloc(256, 8, 256);
296     test_aligned_offset_malloc(256, 8, 512);
297 
298     test_aligned_realloc(256, 512, 0);
299     test_aligned_realloc(256, 128, 0);
300     test_aligned_realloc(256, 512, 4);
301     test_aligned_realloc(256, 128, 4);
302     test_aligned_realloc(256, 512, 8);
303     test_aligned_realloc(256, 128, 8);
304     test_aligned_realloc(256, 512, 16);
305     test_aligned_realloc(256, 128, 16);
306     test_aligned_realloc(256, 512, 32);
307     test_aligned_realloc(256, 128, 32);
308     test_aligned_realloc(256, 512, 64);
309     test_aligned_realloc(256, 128, 64);
310 
311     test_aligned_offset_realloc(256, 512, 0, 0);
312     test_aligned_offset_realloc(256, 128, 0, 0);
313     test_aligned_offset_realloc(256, 512, 4, 0);
314     test_aligned_offset_realloc(256, 128, 4, 0);
315     test_aligned_offset_realloc(256, 512, 8, 0);
316     test_aligned_offset_realloc(256, 128, 8, 0);
317     test_aligned_offset_realloc(256, 512, 16, 0);
318     test_aligned_offset_realloc(256, 128, 16, 0);
319     test_aligned_offset_realloc(256, 512, 32, 0);
320     test_aligned_offset_realloc(256, 128, 32, 0);
321     test_aligned_offset_realloc(256, 512, 64, 0);
322     test_aligned_offset_realloc(256, 128, 64, 0);
323 
324     test_aligned_offset_realloc(256, 512, 0, 4);
325     test_aligned_offset_realloc(256, 128, 0, 4);
326     test_aligned_offset_realloc(256, 512, 4, 4);
327     test_aligned_offset_realloc(256, 128, 4, 4);
328     test_aligned_offset_realloc(256, 512, 8, 4);
329     test_aligned_offset_realloc(256, 128, 8, 4);
330     test_aligned_offset_realloc(256, 512, 16, 4);
331     test_aligned_offset_realloc(256, 128, 16, 4);
332     test_aligned_offset_realloc(256, 512, 32, 4);
333     test_aligned_offset_realloc(256, 128, 32, 4);
334     test_aligned_offset_realloc(256, 512, 64, 4);
335     test_aligned_offset_realloc(256, 128, 64, 4);
336 
337     test_aligned_offset_realloc(256, 512, 0, 8);
338     test_aligned_offset_realloc(256, 128, 0, 8);
339     test_aligned_offset_realloc(256, 512, 4, 8);
340     test_aligned_offset_realloc(256, 128, 4, 8);
341     test_aligned_offset_realloc(256, 512, 8, 8);
342     test_aligned_offset_realloc(256, 128, 8, 8);
343     test_aligned_offset_realloc(256, 512, 16, 8);
344     test_aligned_offset_realloc(256, 128, 16, 8);
345     test_aligned_offset_realloc(256, 512, 32, 8);
346     test_aligned_offset_realloc(256, 128, 32, 8);
347     test_aligned_offset_realloc(256, 512, 64, 8);
348     test_aligned_offset_realloc(256, 128, 64, 8);
349 
350     test_aligned_offset_realloc(256, 512, 0, 16);
351     test_aligned_offset_realloc(256, 128, 0, 16);
352     test_aligned_offset_realloc(256, 512, 4, 16);
353     test_aligned_offset_realloc(256, 128, 4, 16);
354     test_aligned_offset_realloc(256, 512, 8, 16);
355     test_aligned_offset_realloc(256, 128, 8, 16);
356     test_aligned_offset_realloc(256, 512, 16, 16);
357     test_aligned_offset_realloc(256, 128, 16, 16);
358     test_aligned_offset_realloc(256, 512, 32, 16);
359     test_aligned_offset_realloc(256, 128, 32, 16);
360     test_aligned_offset_realloc(256, 512, 64, 16);
361     test_aligned_offset_realloc(256, 128, 64, 16);
362 
363     test_aligned_offset_realloc(256, 512, 0, 32);
364     test_aligned_offset_realloc(256, 128, 0, 32);
365     test_aligned_offset_realloc(256, 512, 4, 32);
366     test_aligned_offset_realloc(256, 128, 4, 32);
367     test_aligned_offset_realloc(256, 512, 8, 32);
368     test_aligned_offset_realloc(256, 128, 8, 32);
369     test_aligned_offset_realloc(256, 512, 16, 32);
370     test_aligned_offset_realloc(256, 128, 16, 32);
371     test_aligned_offset_realloc(256, 512, 32, 32);
372     test_aligned_offset_realloc(256, 128, 32, 32);
373     test_aligned_offset_realloc(256, 512, 64, 32);
374     test_aligned_offset_realloc(256, 128, 64, 32);
375 
376     test_aligned_offset_realloc(256, 512, 0, 64);
377     test_aligned_offset_realloc(256, 128, 0, 64);
378     test_aligned_offset_realloc(256, 512, 4, 64);
379     test_aligned_offset_realloc(256, 128, 4, 64);
380     test_aligned_offset_realloc(256, 512, 8, 64);
381     test_aligned_offset_realloc(256, 128, 8, 64);
382     test_aligned_offset_realloc(256, 512, 16, 64);
383     test_aligned_offset_realloc(256, 128, 16, 64);
384     test_aligned_offset_realloc(256, 512, 32, 64);
385     test_aligned_offset_realloc(256, 128, 32, 64);
386     test_aligned_offset_realloc(256, 512, 64, 64);
387     test_aligned_offset_realloc(256, 128, 64, 64);
388 
389     test_aligned_offset_realloc(256, 512, 0, 96);
390     test_aligned_offset_realloc(256, 128, 0, 96);
391     test_aligned_offset_realloc(256, 512, 4, 96);
392     test_aligned_offset_realloc(256, 128, 4, 96);
393     test_aligned_offset_realloc(256, 512, 8, 96);
394     test_aligned_offset_realloc(256, 128, 8, 96);
395     test_aligned_offset_realloc(256, 512, 16, 96);
396     test_aligned_offset_realloc(256, 128, 16, 96);
397     test_aligned_offset_realloc(256, 512, 32, 96);
398     test_aligned_offset_realloc(256, 128, 32, 96);
399     test_aligned_offset_realloc(256, 512, 64, 96);
400     test_aligned_offset_realloc(256, 128, 64, 96);
401 
402     test_aligned_offset_realloc(256, 512, 0, 112);
403     test_aligned_offset_realloc(256, 128, 0, 112);
404     test_aligned_offset_realloc(256, 512, 4, 112);
405     test_aligned_offset_realloc(256, 128, 4, 112);
406     test_aligned_offset_realloc(256, 512, 8, 112);
407     test_aligned_offset_realloc(256, 128, 8, 112);
408     test_aligned_offset_realloc(256, 512, 16, 112);
409     test_aligned_offset_realloc(256, 128, 16, 112);
410     test_aligned_offset_realloc(256, 512, 32, 112);
411     test_aligned_offset_realloc(256, 128, 32, 112);
412     test_aligned_offset_realloc(256, 512, 64, 112);
413     test_aligned_offset_realloc(256, 128, 64, 112);
414 }
415 
416 static void test_sbheap(void)
417 {
418     void *mem;
419     int threshold;
420 
421     if(sizeof(void*) == 8) {
422         ok(!_set_sbh_threshold(0), "_set_sbh_threshold succeeded\n");
423         ok(!_set_sbh_threshold(1000), "_set_sbh_threshold succeeded\n");
424         return;
425     }
426 
427     mem = malloc(1);
428     ok(mem != NULL, "malloc failed\n");
429 
430     ok(_set_sbh_threshold(1), "_set_sbh_threshold failed\n");
431     threshold = _get_sbh_threshold();
432     ok(threshold == 16, "threshold = %d\n", threshold);
433 
434     ok(_set_sbh_threshold(8), "_set_sbh_threshold failed\n");
435     threshold = _get_sbh_threshold();
436     ok(threshold == 16, "threshold = %d\n", threshold);
437 
438     ok(_set_sbh_threshold(1000), "_set_sbh_threshold failed\n");
439     threshold = _get_sbh_threshold();
440     ok(threshold == 1008, "threshold = %d\n", threshold);
441 
442     free(mem);
443 
444     mem = malloc(1);
445     ok(mem != NULL, "malloc failed\n");
446     ok(!((UINT_PTR)mem & 0xf), "incorrect alignment (%p)\n", mem);
447 
448     mem = realloc(mem, 10);
449     ok(mem != NULL, "realloc failed\n");
450     ok(!((UINT_PTR)mem & 0xf), "incorrect alignment (%p)\n", mem);
451 
452     ok(_set_sbh_threshold(0), "_set_sbh_threshold failed\n");
453     threshold = _get_sbh_threshold();
454     ok(threshold == 0, "threshold = %d\n", threshold);
455 
456     free(mem);
457 }
458 
459 static void test_calloc(void)
460 {
461     void *ptr;
462 
463     ptr = calloc(1, 0);
464     ok(ptr != NULL, "got %p\n", ptr);
465     free(ptr);
466 
467     ptr = calloc(0, 0);
468     ok(ptr != NULL, "got %p\n", ptr);
469     free(ptr);
470 
471     ptr = calloc(0, 1);
472     ok(ptr != NULL, "got %p\n", ptr);
473     free(ptr);
474 
475     errno = 0;
476     ptr = calloc(~(size_t)0 / 2, ~(size_t)0 / 2);
477     ok(ptr == NULL || broken(ptr != NULL) /* winxp sp0 */, "got %p\n", ptr);
478     ok(errno == ENOMEM || broken(errno == 0) /* winxp, win2k3 */, "got errno %d\n", errno);
479     free(ptr);
480 }
481 
482 START_TEST(heap)
483 {
484     void *mem;
485 
486     mem = malloc(0);
487     ok(mem != NULL, "memory not allocated for size 0\n");
488     free(mem);
489 
490     mem = realloc(NULL, 10);
491     ok(mem != NULL, "memory not allocated\n");
492 
493     mem = realloc(mem, 20);
494     ok(mem != NULL, "memory not reallocated\n");
495 
496     mem = realloc(mem, 0);
497     ok(mem == NULL, "memory not freed\n");
498 
499     mem = realloc(NULL, 0);
500     ok(mem != NULL, "memory not (re)allocated for size 0\n");
501 
502     free(mem);
503 
504     test_aligned();
505     test_sbheap();
506     test_calloc();
507 }
508