kernel32: Rewrote toolhelp implementation only on top of ntdll functions.
[wine] / dlls / kernel / tests / alloc.c
1 /*
2  * Unit test suite for memory allocation functions.
3  *
4  * Copyright 2002 Geoffrey Hausheer
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "wine/test.h"
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27
28
29  /* The following functions don't have tests, because either I don't know how
30    to test them, or they are WinNT only, or require multiple threads.
31    Since the last two issues shouldn't really stop the tests from being
32    written, assume for now that it is all due to the first case
33        HeapCompact
34        HeapLock
35        HeapQueryInformation
36        HeapSetInformation
37        HeapUnlock
38        HeapValidate
39        HeapWalk
40 */
41 /* In addition, these features aren't being tested
42        HEAP_NO_SERIALIZE
43        HEAP_GENERATE_EXCEPTIONS
44        STATUS_ACCESS_VIOLATION (error code from HeapAlloc)
45 */
46
47 static void test_Heap(void)
48 {
49     SYSTEM_INFO sysInfo;
50     ULONG memchunk;
51     HANDLE heap;
52     LPVOID mem1,mem1a,mem3;
53     UCHAR *mem2,*mem2a;
54     UINT error,i;
55     DWORD dwSize;
56
57 /* Retrieve the page size for this system */
58     sysInfo.dwPageSize=0;
59     GetSystemInfo(&sysInfo);
60     ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
61
62 /* Create a Heap with a minimum and maximum size */
63 /* Note that Windows and Wine seem to behave a bit differently with respect
64    to memory allocation.  In Windows, you can't access all the memory
65    specified in the heap (due to overhead), so choosing a reasonable maximum
66    size for the heap was done mostly by trial-and-error on Win2k.  It may need
67    more tweaking for otherWindows variants.
68 */
69     memchunk=10*sysInfo.dwPageSize;
70     heap=HeapCreate(0,2*memchunk,5*memchunk);
71
72 /* Check that HeapCreate allocated the right amount of ram */
73     todo_wine {
74     /* Today HeapCreate seems to return a memory block larger than specified.
75        MSDN says the maximum heap size should be dwMaximumSize rounded up to the
76        nearest page boundary
77     */
78       mem1=HeapAlloc(heap,0,5*memchunk+1);
79       ok(mem1==NULL,"HeapCreate allocated more Ram than it should have\n");
80       HeapFree(heap,0,mem1);
81     }
82
83 /* Check that a normal alloc works */
84     mem1=HeapAlloc(heap,0,memchunk);
85     ok(mem1!=NULL,"HeapAlloc failed\n");
86     if(mem1) {
87       ok(HeapSize(heap,0,mem1)>=memchunk, "HeapAlloc should return a big enough memory block\n");
88     }
89
90 /* Check that a 'zeroing' alloc works */
91     mem2=HeapAlloc(heap,HEAP_ZERO_MEMORY,memchunk);
92     ok(mem2!=NULL,"HeapAlloc failed\n");
93     if(mem2) {
94       ok(HeapSize(heap,0,mem2)>=memchunk,"HeapAlloc should return a big enough memory block\n");
95       error=0;
96       for(i=0;i<memchunk;i++) {
97         if(mem2[i]!=0) {
98           error=1;
99         }
100       }
101       ok(!error,"HeapAlloc should have zeroed out it's allocated memory\n");
102     }
103
104 /* Check that HeapAlloc returns NULL when requested way too much memory */
105     mem3=HeapAlloc(heap,0,5*memchunk);
106     ok(mem3==NULL,"HeapAlloc should return NULL\n");
107     if(mem3) {
108       ok(HeapFree(heap,0,mem3),"HeapFree didn't pass successfully\n");
109     }
110
111 /* Check that HeapRealloc works */
112     mem2a=HeapReAlloc(heap,HEAP_ZERO_MEMORY,mem2,memchunk+5*sysInfo.dwPageSize);
113     ok(mem2a!=NULL,"HeapReAlloc failed\n");
114     if(mem2a) {
115       ok(HeapSize(heap,0,mem2a)>=memchunk+5*sysInfo.dwPageSize,"HeapReAlloc failed\n");
116       error=0;
117       for(i=0;i<5*sysInfo.dwPageSize;i++) {
118         if(mem2a[memchunk+i]!=0) {
119           error=1;
120         }
121       }
122       ok(!error,"HeapReAlloc should have zeroed out it's allocated memory\n");
123     }
124
125 /* Check that HeapRealloc honours HEAP_REALLOC_IN_PLACE_ONLY */
126     error=0;
127     mem1a=HeapReAlloc(heap,HEAP_REALLOC_IN_PLACE_ONLY,mem1,memchunk+sysInfo.dwPageSize);
128     if(mem1a!=NULL) {
129       if(mem1a!=mem1) {
130         error=1;
131       }
132     }
133     ok(mem1a==NULL || error==0,"HeapReAlloc didn't honour HEAP_REALLOC_IN_PLACE_ONLY\n");
134
135 /* Check that HeapFree works correctly */
136    if(mem1a) {
137      ok(HeapFree(heap,0,mem1a),"HeapFree failed\n");
138    } else {
139      ok(HeapFree(heap,0,mem1),"HeapFree failed\n");
140    }
141    if(mem2a) {
142      ok(HeapFree(heap,0,mem2a),"HeapFree failed\n");
143    } else {
144      ok(HeapFree(heap,0,mem2),"HeapFree failed\n");
145    }
146
147    /* 0-length buffer */
148    mem1 = HeapAlloc(heap, 0, 0);
149    ok(mem1 != NULL, "Reserved memory\n");
150
151    dwSize = HeapSize(heap, 0, mem1);
152    /* should work with 0-length buffer */
153    ok((dwSize >= 0) && (dwSize < 0xFFFFFFFF),
154       "The size of the 0-length buffer\n");
155    ok(HeapFree(heap, 0, mem1), "Freed the 0-length buffer\n");
156
157 /* Check that HeapDestry works */
158    ok(HeapDestroy(heap),"HeapDestroy failed\n");
159 }
160
161 /* The following functions don't have tests, because either I don't know how
162    to test them, or they are WinNT only, or require multiple threads.
163    Since the last two issues shouldn't really stop the tests from being
164    written, assume for now that it is all due to the first case
165        GlobalFlags
166        GlobalMemoryStatus
167        GlobalMemoryStatusEx
168 */
169 /* In addition, these features aren't being tested
170        GMEM_DISCADABLE
171        GMEM_NOCOMPACT
172 */
173 static void test_Global(void)
174 {
175     ULONG memchunk;
176     HGLOBAL mem1,mem2,mem2a,mem2b;
177     UCHAR *mem2ptr;
178     UINT error,i;
179     memchunk=100000;
180
181     SetLastError(NO_ERROR);
182 /* Check that a normal alloc works */
183     mem1=GlobalAlloc(0,memchunk);
184     ok(mem1!=NULL,"GlobalAlloc failed\n");
185     if(mem1) {
186       ok(GlobalSize(mem1)>=memchunk, "GlobalAlloc should return a big enough memory block\n");
187     }
188
189 /* Check that a 'zeroing' alloc works */
190     mem2=GlobalAlloc(GMEM_ZEROINIT,memchunk);
191     ok(mem2!=NULL,"GlobalAlloc failed: error=%ld\n",GetLastError());
192     if(mem2) {
193       ok(GlobalSize(mem2)>=memchunk,"GlobalAlloc should return a big enough memory block\n");
194       mem2ptr=GlobalLock(mem2);
195       ok(mem2ptr==mem2,"GlobalLock should have returned the same memory as was allocated\n");
196       if(mem2ptr) {
197         error=0;
198         for(i=0;i<memchunk;i++) {
199           if(mem2ptr[i]!=0) {
200             error=1;
201           }
202         }
203         ok(!error,"GlobalAlloc should have zeroed out it's allocated memory\n");
204       }
205    }
206 /* Check that GlobalReAlloc works */
207 /* Check that we can change GMEM_FIXED to GMEM_MOVEABLE */
208     mem2a=GlobalReAlloc(mem2,0,GMEM_MODIFY | GMEM_MOVEABLE);
209     if(mem2a!=NULL) {
210       mem2=mem2a;
211       mem2ptr=GlobalLock(mem2a);
212       ok(mem2ptr!=NULL && !GlobalUnlock(mem2a)&&GetLastError()==NO_ERROR,
213          "Converting from FIXED to MOVEABLE didn't REALLY work\n");
214     }
215
216 /* Check that ReAllocing memory works as expected */
217     mem2a=GlobalReAlloc(mem2,2*memchunk,GMEM_MOVEABLE | GMEM_ZEROINIT);
218     ok(mem2a!=NULL,"GlobalReAlloc failed\n");
219     if(mem2a) {
220       ok(GlobalSize(mem2a)>=2*memchunk,"GlobalReAlloc failed\n");
221       mem2ptr=GlobalLock(mem2a);
222       ok(mem2ptr!=NULL,"GlobalLock Failed\n");
223       if(mem2ptr) {
224         error=0;
225         for(i=0;i<memchunk;i++) {
226           if(mem2ptr[memchunk+i]!=0) {
227             error=1;
228           }
229         }
230         ok(!error,"GlobalReAlloc should have zeroed out it's allocated memory\n");
231
232 /* Check that GlobalHandle works */
233         mem2b=GlobalHandle(mem2ptr);
234         ok(mem2b==mem2a,"GlobalHandle didn't return the correct memory handle\n");
235
236 /* Check that we can't discard locked memory */
237         mem2b=GlobalDiscard(mem2a);
238         if(mem2b==NULL) {
239           ok(!GlobalUnlock(mem2a) && GetLastError()==NO_ERROR,"GlobalUnlock Failed\n");
240         }
241       }
242     }
243     if(mem1) {
244       ok(GlobalFree(mem1)==NULL,"GlobalFree failed\n");
245     }
246     if(mem2a) {
247       ok(GlobalFree(mem2a)==NULL,"GlobalFree failed\n");
248     } else {
249       ok(GlobalFree(mem2)==NULL,"GlobalFree failed\n");
250     }
251 }
252
253
254 /* The following functions don't have tests, because either I don't know how
255    to test them, or they are WinNT only, or require multiple threads.
256    Since the last two issues shouldn't really stop the tests from being
257    written, assume for now that it is all due to the first case
258        LocalDiscard
259        LocalFlags
260 */
261 /* In addition, these features aren't being tested
262        LMEM_DISCADABLE
263        LMEM_NOCOMPACT
264 */
265 static void test_Local(void)
266 {
267     ULONG memchunk;
268     HLOCAL mem1,mem2,mem2a,mem2b;
269     UCHAR *mem2ptr;
270     UINT error,i;
271     memchunk=100000;
272
273 /* Check that a normal alloc works */
274     mem1=LocalAlloc(0,memchunk);
275     ok(mem1!=NULL,"LocalAlloc failed: error=%ld\n",GetLastError());
276     if(mem1) {
277       ok(LocalSize(mem1)>=memchunk, "LocalAlloc should return a big enough memory block\n");
278     }
279
280 /* Check that a 'zeroing' and lock alloc works */
281     mem2=LocalAlloc(LMEM_ZEROINIT|LMEM_MOVEABLE,memchunk);
282     ok(mem2!=NULL,"LocalAlloc failed: error=%ld\n",GetLastError());
283     if(mem2) {
284       ok(LocalSize(mem2)>=memchunk,"LocalAlloc should return a big enough memory block\n");
285       mem2ptr=LocalLock(mem2);
286       ok(mem2ptr!=NULL,"LocalLock: error=%ld\n",GetLastError());
287       if(mem2ptr) {
288         error=0;
289         for(i=0;i<memchunk;i++) {
290           if(mem2ptr[i]!=0) {
291             error=1;
292           }
293         }
294         ok(!error,"LocalAlloc should have zeroed out it's allocated memory\n");
295         SetLastError(0);
296         error=LocalUnlock(mem2);
297         ok(error==0 && GetLastError()==NO_ERROR,
298            "LocalUnlock Failed: rc=%d err=%ld\n",error,GetLastError());
299       }
300     }
301    mem2a=LocalFree(mem2);
302    ok(mem2a==NULL, "LocalFree failed: %p\n",mem2a);
303
304 /* Reallocate mem2 as moveable memory */
305    mem2=LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,memchunk);
306    ok(mem2!=NULL, "LocalAlloc failed to create moveable memory, error=%ld\n",GetLastError());
307
308 /* Check that ReAllocing memory works as expected */
309     mem2a=LocalReAlloc(mem2,2*memchunk,LMEM_MOVEABLE | LMEM_ZEROINIT);
310     ok(mem2a!=NULL,"LocalReAlloc failed, error=%ld\n",GetLastError());
311     if(mem2a) {
312       ok(LocalSize(mem2a)>=2*memchunk,"LocalReAlloc failed\n");
313       mem2ptr=LocalLock(mem2a);
314       ok(mem2ptr!=NULL,"LocalLock Failed\n");
315       if(mem2ptr) {
316         error=0;
317         for(i=0;i<memchunk;i++) {
318           if(mem2ptr[memchunk+i]!=0) {
319             error=1;
320           }
321         }
322         ok(!error,"LocalReAlloc should have zeroed out it's allocated memory\n");
323 /* Check that LocalHandle works */
324         mem2b=LocalHandle(mem2ptr);
325         ok(mem2b==mem2a,"LocalHandle didn't return the correct memory handle\n");
326 /* Check that we can't discard locked memory */
327         mem2b=LocalDiscard(mem2a);
328         ok(mem2b==NULL,"Discarded memory we shouldn't have\n");
329         SetLastError(NO_ERROR);
330         ok(!LocalUnlock(mem2a) && GetLastError()==NO_ERROR, "LocalUnlock Failed\n");
331       }
332     }
333     if(mem1) {
334       ok(LocalFree(mem1)==NULL,"LocalFree failed\n");
335     }
336     if(mem2a) {
337       ok(LocalFree(mem2a)==NULL,"LocalFree failed\n");
338     } else {
339       ok(LocalFree(mem2)==NULL,"LocalFree failed\n");
340     }
341 }
342
343 /* The Virtual* routines are not tested as thoroughly,
344    since I don't really understand how to use them correctly :)
345    The following routines are not tested at all
346       VirtualAllocEx
347       VirtualFreeEx
348       VirtualLock
349       VirtualProtect
350       VirtualProtectEx
351       VirtualQuery
352       VirtualQueryEx
353       VirtualUnlock
354     And the only features (flags) being tested are
355       MEM_COMMIT
356       MEM_RELEASE
357       PAGE_READWRITE
358     Testing the rest requires using exceptions, which I really don't
359     understand well
360 */
361 static void test_Virtual(void)
362 {
363     SYSTEM_INFO sysInfo;
364     ULONG memchunk;
365     UCHAR *mem1;
366     UINT error,i;
367
368 /* Retrieve the page size for this system */
369     sysInfo.dwPageSize=0;
370     GetSystemInfo(&sysInfo);
371     ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
372
373 /* Choose a reasonable allocation size */
374     memchunk=10*sysInfo.dwPageSize;
375
376 /* Check that a normal alloc works */
377     mem1=VirtualAlloc(NULL,memchunk,MEM_COMMIT,PAGE_READWRITE);
378     ok(mem1!=NULL,"VirtualAlloc failed\n");
379     if(mem1) {
380 /* check that memory is initialized to 0 */
381       error=0;
382       for(i=0;i<memchunk;i++) {
383         if(mem1[i]!=0) {
384           error=1;
385         }
386       }
387       ok(!error,"VirtualAlloc did not initialize memory to '0's\n");
388 /* Check that we can read/write to memory */
389       error=0;
390       for(i=0;i<memchunk;i+=100) {
391         mem1[i]='a';
392         if(mem1[i]!='a') {
393           error=1;
394         }
395       }
396       ok(!error,"Virtual memory was not writable\n");
397     }
398     ok(VirtualFree(mem1,0,MEM_RELEASE),"VirtualFree failed\n");
399 }
400 START_TEST(alloc)
401 {
402     test_Heap();
403     test_Global();
404     test_Local();
405     test_Virtual();
406 }