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