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