Set the WINEPRELOADRESERVE variable when starting a new process.
[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       if(mem1) {
81         HeapFree(heap,0,mem1);
82       }
83     }
84
85 /* Check that a normal alloc works */
86     mem1=HeapAlloc(heap,0,memchunk);
87     ok(mem1!=NULL,"HeapAlloc failed\n");
88     if(mem1) {
89       ok(HeapSize(heap,0,mem1)>=memchunk, "HeapAlloc should return a big enough memory block\n");
90     }
91
92 /* Check that a 'zeroing' alloc works */
93     mem2=HeapAlloc(heap,HEAP_ZERO_MEMORY,memchunk);
94     ok(mem2!=NULL,"HeapAlloc failed\n");
95     if(mem2) {
96       ok(HeapSize(heap,0,mem2)>=memchunk,"HeapAlloc should return a big enough memory block\n");
97       error=0;
98       for(i=0;i<memchunk;i++) {
99         if(mem2[i]!=0) {
100           error=1;
101         }
102       }
103       ok(!error,"HeapAlloc should have zeroed out it's allocated memory\n");
104     }
105
106 /* Check that HeapAlloc returns NULL when requested way too much memory */
107     mem3=HeapAlloc(heap,0,5*memchunk);
108     ok(mem3==NULL,"HeapAlloc should return NULL\n");
109     if(mem3) {
110       ok(HeapFree(heap,0,mem3),"HeapFree didn't pass successfully\n");
111     }
112
113 /* Check that HeapRealloc works */
114     mem2a=HeapReAlloc(heap,HEAP_ZERO_MEMORY,mem2,memchunk+5*sysInfo.dwPageSize);
115     ok(mem2a!=NULL,"HeapReAlloc failed\n");
116     if(mem2a) {
117       ok(HeapSize(heap,0,mem2a)>=memchunk+5*sysInfo.dwPageSize,"HeapReAlloc failed\n");
118       error=0;
119       for(i=0;i<5*sysInfo.dwPageSize;i++) {
120         if(mem2a[memchunk+i]!=0) {
121           error=1;
122         }
123       }
124       ok(!error,"HeapReAlloc should have zeroed out it's allocated memory\n");
125     }
126
127 /* Check that HeapRealloc honours HEAP_REALLOC_IN_PLACE_ONLY */
128     error=0;
129     mem1a=HeapReAlloc(heap,HEAP_REALLOC_IN_PLACE_ONLY,mem1,memchunk+sysInfo.dwPageSize);
130     if(mem1a!=NULL) {
131       if(mem1a!=mem1) {
132         error=1;
133       }
134     }
135     ok(mem1a==NULL || error==0,"HeapReAlloc didn't honour HEAP_REALLOC_IN_PLACE_ONLY\n");
136
137 /* Check that HeapFree works correctly */
138    if(mem1a) {
139      ok(HeapFree(heap,0,mem1a),"HeapFree failed\n");
140    } else {
141      ok(HeapFree(heap,0,mem1),"HeapFree failed\n");
142    }
143    if(mem2a) {
144      ok(HeapFree(heap,0,mem2a),"HeapFree failed\n");
145    } else {
146      ok(HeapFree(heap,0,mem2),"HeapFree failed\n");
147    }
148
149    /* 0-length buffer */
150    mem1 = HeapAlloc(heap, 0, 0);
151    ok(mem1 != NULL, "Reserved memory\n");
152
153    dwSize = HeapSize(heap, 0, mem1);
154    /* should work with 0-length buffer */
155    ok((dwSize >= 0) && (dwSize < 0xFFFFFFFF),
156       "The size of the 0-length buffer\n");
157    ok(HeapFree(heap, 0, mem1), "Freed the 0-length buffer\n");
158
159 /* Check that HeapDestry works */
160    ok(HeapDestroy(heap),"HeapDestroy failed\n");
161 }
162
163 /* The following functions don't have tests, because either I don't know how
164    to test them, or they are WinNT only, or require multiple threads.
165    Since the last two issues shouldn't really stop the tests from being
166    written, assume for now that it is all due to the first case
167        GlobalFlags
168        GlobalMemoryStatus
169        GlobalMemoryStatusEx
170 */
171 /* In addition, these features aren't being tested
172        GMEM_DISCADABLE
173        GMEM_NOCOMPACT
174 */
175 static void test_Global(void)
176 {
177     ULONG memchunk;
178     HGLOBAL mem1,mem2,mem2a,mem2b;
179     UCHAR *mem2ptr;
180     UINT error,i;
181     memchunk=100000;
182
183     SetLastError(NO_ERROR);
184 /* Check that a normal alloc works */
185     mem1=GlobalAlloc(0,memchunk);
186     ok(mem1!=NULL,"GlobalAlloc failed\n");
187     if(mem1) {
188       ok(GlobalSize(mem1)>=memchunk, "GlobalAlloc should return a big enough memory block\n");
189     }
190
191 /* Check that a 'zeroing' alloc works */
192     mem2=GlobalAlloc(GMEM_ZEROINIT,memchunk);
193     ok(mem2!=NULL,"GlobalAlloc failed: error=%ld\n",GetLastError());
194     if(mem2) {
195       ok(GlobalSize(mem2)>=memchunk,"GlobalAlloc should return a big enough memory block\n");
196       mem2ptr=GlobalLock(mem2);
197       ok(mem2ptr==mem2,"GlobalLock should have returned the same memory as was allocated\n");
198       if(mem2ptr) {
199         error=0;
200         for(i=0;i<memchunk;i++) {
201           if(mem2ptr[i]!=0) {
202             error=1;
203           }
204         }
205         ok(!error,"GlobalAlloc should have zeroed out it's allocated memory\n");
206       }
207    }
208 /* Check that GlobalReAlloc works */
209 /* Check that we can change GMEM_FIXED to GMEM_MOVEABLE */
210     mem2a=GlobalReAlloc(mem2,0,GMEM_MODIFY | GMEM_MOVEABLE);
211     ok(mem2a!=NULL,"GlobalReAlloc failed to convert FIXED to MOVEABLE: error=%ld\n",GetLastError());
212     if(mem2a!=NULL) {
213       mem2=mem2a;
214     }
215     mem2ptr=GlobalLock(mem2a);
216     ok(mem2ptr!=NULL && !GlobalUnlock(mem2a)&&GetLastError()==NO_ERROR,
217         "Converting from FIXED to MOVEABLE didn't REALLY work\n");
218
219 /* Check that ReAllocing memory works as expected */
220     mem2a=GlobalReAlloc(mem2,2*memchunk,GMEM_MOVEABLE | GMEM_ZEROINIT);
221     ok(mem2a!=NULL,"GlobalReAlloc failed\n");
222     if(mem2a) {
223       ok(GlobalSize(mem2a)>=2*memchunk,"GlobalReAlloc failed\n");
224       mem2ptr=GlobalLock(mem2a);
225       ok(mem2ptr!=NULL,"GlobalLock Failed\n");
226       if(mem2ptr) {
227         error=0;
228         for(i=0;i<memchunk;i++) {
229           if(mem2ptr[memchunk+i]!=0) {
230             error=1;
231           }
232         }
233         ok(!error,"GlobalReAlloc should have zeroed out it's allocated memory\n");
234
235 /* Check that GlobalHandle works */
236         mem2b=GlobalHandle(mem2ptr);
237         ok(mem2b==mem2a,"GlobalHandle didn't return the correct memory handle\n");
238
239 /* Check that we can't discard locked memory */
240         mem2b=GlobalDiscard(mem2a);
241         ok(mem2b==NULL,"Discarded memory we shouldn't have\n");
242         ok(!GlobalUnlock(mem2a) && GetLastError()==NO_ERROR,"GlobalUnlock Failed\n");
243       }
244     }
245     if(mem1) {
246       ok(GlobalFree(mem1)==NULL,"GlobalFree failed\n");
247     }
248     if(mem2a) {
249       ok(GlobalFree(mem2a)==NULL,"GlobalFree failed\n");
250     } else {
251       ok(GlobalFree(mem2)==NULL,"GlobalFree failed\n");
252     }
253 }
254
255
256 /* The following functions don't have tests, because either I don't know how
257    to test them, or they are WinNT only, or require multiple threads.
258    Since the last two issues shouldn't really stop the tests from being
259    written, assume for now that it is all due to the first case
260        LocalDiscard
261        LocalFlags
262 */
263 /* In addition, these features aren't being tested
264        LMEM_DISCADABLE
265        LMEM_NOCOMPACT
266 */
267 static void test_Local(void)
268 {
269     ULONG memchunk;
270     HLOCAL mem1,mem2,mem2a,mem2b;
271     UCHAR *mem2ptr;
272     UINT error,i;
273     memchunk=100000;
274
275 /* Check that a normal alloc works */
276     mem1=LocalAlloc(0,memchunk);
277     ok(mem1!=NULL,"LocalAlloc failed: error=%ld\n",GetLastError());
278     if(mem1) {
279       ok(LocalSize(mem1)>=memchunk, "LocalAlloc should return a big enough memory block\n");
280     }
281
282 /* Check that a 'zeroing' and lock alloc works */
283     mem2=LocalAlloc(LMEM_ZEROINIT|LMEM_MOVEABLE,memchunk);
284     ok(mem2!=NULL,"LocalAlloc failed: error=%ld\n",GetLastError());
285     if(mem2) {
286       ok(LocalSize(mem2)>=memchunk,"LocalAlloc should return a big enough memory block\n");
287       mem2ptr=LocalLock(mem2);
288       ok(mem2ptr!=NULL,"LocalLock: error=%ld\n",GetLastError());
289       if(mem2ptr) {
290         error=0;
291         for(i=0;i<memchunk;i++) {
292           if(mem2ptr[i]!=0) {
293             error=1;
294           }
295         }
296         ok(!error,"LocalAlloc should have zeroed out it's allocated memory\n");
297         SetLastError(0);
298         error=LocalUnlock(mem2);
299         ok(error==0 && GetLastError()==NO_ERROR,
300            "LocalUnlock Failed: rc=%d err=%ld\n",error,GetLastError());
301       }
302     }
303    mem2a=LocalFree(mem2);
304    ok(mem2a==NULL, "LocalFree failed: %p\n",mem2a);
305
306 /* Reallocate mem2 as moveable memory */
307    mem2=LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,memchunk);
308    ok(mem2!=NULL, "LocalAlloc failed to create moveable memory, error=%ld\n",GetLastError());
309
310 /* Check that ReAllocing memory works as expected */
311     mem2a=LocalReAlloc(mem2,2*memchunk,LMEM_MOVEABLE | LMEM_ZEROINIT);
312     ok(mem2a!=NULL,"LocalReAlloc failed, error=%ld\n",GetLastError());
313     if(mem2a) {
314       ok(LocalSize(mem2a)>=2*memchunk,"LocalReAlloc failed\n");
315       mem2ptr=LocalLock(mem2a);
316       ok(mem2ptr!=NULL,"LocalLock Failed\n");
317       if(mem2ptr) {
318         error=0;
319         for(i=0;i<memchunk;i++) {
320           if(mem2ptr[memchunk+i]!=0) {
321             error=1;
322           }
323         }
324         ok(!error,"LocalReAlloc should have zeroed out it's allocated memory\n");
325 /* Check that LocalHandle works */
326         mem2b=LocalHandle(mem2ptr);
327         ok(mem2b==mem2a,"LocalHandle didn't return the correct memory handle\n");
328 /* Check that we can't discard locked memory */
329         mem2b=LocalDiscard(mem2a);
330         ok(mem2b==NULL,"Discarded memory we shouldn't have\n");
331         SetLastError(NO_ERROR);
332         ok(!LocalUnlock(mem2a) && GetLastError()==NO_ERROR, "LocalUnlock Failed\n");
333       }
334     }
335     if(mem1) {
336       ok(LocalFree(mem1)==NULL,"LocalFree failed\n");
337     }
338     if(mem2a) {
339       ok(LocalFree(mem2a)==NULL,"LocalFree failed\n");
340     } else {
341       ok(LocalFree(mem2)==NULL,"LocalFree failed\n");
342     }
343 }
344
345 /* The Virtual* routines are not tested as thoroughly,
346    since I don't really understand how to use them correctly :)
347    The following routines are not tested at all
348       VirtualAllocEx
349       VirtualFreeEx
350       VirtualLock
351       VirtualProtect
352       VirtualProtectEx
353       VirtualQuery
354       VirtualQueryEx
355       VirtualUnlock
356     And the only features (flags) being tested are
357       MEM_COMMIT
358       MEM_RELEASE
359       PAGE_READWRITE
360     Testing the rest requires using exceptions, which I really don't
361     understand well
362 */
363 static void test_Virtual(void)
364 {
365     SYSTEM_INFO sysInfo;
366     ULONG memchunk;
367     UCHAR *mem1;
368     UINT error,i;
369
370 /* Retrieve the page size for this system */
371     sysInfo.dwPageSize=0;
372     GetSystemInfo(&sysInfo);
373     ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
374
375 /* Choose a reasonable allocation size */
376     memchunk=10*sysInfo.dwPageSize;
377
378 /* Check that a normal alloc works */
379     mem1=VirtualAlloc(NULL,memchunk,MEM_COMMIT,PAGE_READWRITE);
380     ok(mem1!=NULL,"VirtualAlloc failed\n");
381     if(mem1) {
382 /* check that memory is initialized to 0 */
383       error=0;
384       for(i=0;i<memchunk;i++) {
385         if(mem1[i]!=0) {
386           error=1;
387         }
388       }
389       ok(!error,"VirtualAlloc did not initialize memory to '0's\n");
390 /* Check that we can read/write to memory */
391       error=0;
392       for(i=0;i<memchunk;i+=100) {
393         mem1[i]='a';
394         if(mem1[i]!='a') {
395           error=1;
396         }
397       }
398       ok(!error,"Virtual memory was not writable\n");
399     }
400     ok(VirtualFree(mem1,0,MEM_RELEASE),"VirtualFree failed\n");
401 }
402 START_TEST(alloc)
403 {
404     test_Heap();
405     test_Global();
406     test_Local();
407     test_Virtual();
408 }