1 /*
2  * Unit test suite for heap functions
3  *
4  * Copyright 2002 Geoffrey Hausheer
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2006 Detlef Riekenberg
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "wine/winternl.h"
31 #include "wine/test.h"
32 
33 #define MAGIC_DEAD 0xdeadbeef
34 
35 /* some undocumented flags (names are made up) */
36 #define HEAP_PAGE_ALLOCS      0x01000000
37 #define HEAP_VALIDATE         0x10000000
38 #define HEAP_VALIDATE_ALL     0x20000000
39 #define HEAP_VALIDATE_PARAMS  0x40000000
40 
41 static BOOL (WINAPI *pHeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
42 static BOOL (WINAPI *pGetPhysicallyInstalledSystemMemory)(ULONGLONG *);
43 static ULONG (WINAPI *pRtlGetNtGlobalFlags)(void);
44 
45 struct heap_layout
46 {
47     DWORD_PTR unknown[2];
48     DWORD pattern;
49     DWORD flags;
50     DWORD force_flags;
51 };
52 
53 static SIZE_T resize_9x(SIZE_T size)
54 {
55     DWORD dwSizeAligned = (size + 3) & ~3;
56     return max(dwSizeAligned, 12); /* at least 12 bytes */
57 }
58 
59 static void test_sized_HeapAlloc(int nbytes)
60 {
61     BOOL success;
62     char *buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbytes);
63     ok(buf != NULL, "allocate failed\n");
64     ok(buf[0] == 0, "buffer not zeroed\n");
65     success = HeapFree(GetProcessHeap(), 0, buf);
66     ok(success, "free failed\n");
67 }
68 
69 static void test_sized_HeapReAlloc(int nbytes1, int nbytes2)
70 {
71     BOOL success;
72     char *buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbytes1);
73     ok(buf != NULL, "allocate failed\n");
74     ok(buf[0] == 0, "buffer not zeroed\n");
75     buf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf, nbytes2);
76     ok(buf != NULL, "reallocate failed\n");
77     ok(buf[nbytes2-1] == 0, "buffer not zeroed\n");
78     success = HeapFree(GetProcessHeap(), 0, buf);
79     ok(success, "free failed\n");
80 }
81 
82 static void test_heap(void)
83 {
84     LPVOID  mem;
85     LPVOID  msecond;
86     DWORD   res;
87     UINT    flags;
88     HGLOBAL gbl;
89     HGLOBAL hsecond;
90     SIZE_T  size, size2;
91     const SIZE_T max_size = 1024, init_size = 10;
92 
93     /* Heap*() functions */
94     mem = HeapAlloc(GetProcessHeap(), 0, 0);
95     ok(mem != NULL, "memory not allocated for size 0\n");
96     HeapFree(GetProcessHeap(), 0, mem);
97 
98     mem = HeapReAlloc(GetProcessHeap(), 0, NULL, 10);
99     ok(mem == NULL, "memory allocated by HeapReAlloc\n");
100 
101     for (size = 0; size <= 256; size++)
102     {
103         SIZE_T heap_size;
104         mem = HeapAlloc(GetProcessHeap(), 0, size);
105         heap_size = HeapSize(GetProcessHeap(), 0, mem);
106         ok(heap_size == size || heap_size == resize_9x(size),
107             "HeapSize returned %lu instead of %lu or %lu\n", heap_size, size, resize_9x(size));
108         HeapFree(GetProcessHeap(), 0, mem);
109     }
110 
111     /* test some border cases of HeapAlloc and HeapReAlloc */
112     mem = HeapAlloc(GetProcessHeap(), 0, 0);
113     ok(mem != NULL, "memory not allocated for size 0\n");
114     msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0 - 7);
115     ok(msecond == NULL, "HeapReAlloc(~0 - 7) should have failed\n");
116     msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0);
117     ok(msecond == NULL, "HeapReAlloc(~0) should have failed\n");
118     HeapFree(GetProcessHeap(), 0, mem);
119     mem = HeapAlloc(GetProcessHeap(), 0, ~(SIZE_T)0);
120     ok(mem == NULL, "memory allocated for size ~0\n");
121     mem = HeapAlloc(GetProcessHeap(), 0, 17);
122     msecond = HeapReAlloc(GetProcessHeap(), 0, mem, 0);
123     ok(msecond != NULL, "HeapReAlloc(0) should have succeeded\n");
124     size = HeapSize(GetProcessHeap(), 0, msecond);
125     ok(size == 0 || broken(size == 1) /* some vista and win7 */,
126        "HeapSize should have returned 0 instead of %lu\n", size);
127     HeapFree(GetProcessHeap(), 0, msecond);
128 
129     /* large blocks must be 16-byte aligned */
130     mem = HeapAlloc(GetProcessHeap(), 0, 512 * 1024);
131     ok( mem != NULL, "failed for size 512K\n" );
132     ok( (ULONG_PTR)mem % 16 == 0 || broken((ULONG_PTR)mem % 16) /* win9x */,
133         "512K block not 16-byte aligned\n" );
134     HeapFree(GetProcessHeap(), 0, mem);
135 
136     /* Global*() functions */
137     gbl = GlobalAlloc(GMEM_MOVEABLE, 0);
138     ok(gbl != NULL, "global memory not allocated for size 0\n");
139 
140     gbl = GlobalReAlloc(gbl, 10, GMEM_MOVEABLE);
141     ok(gbl != NULL, "Can't realloc global memory\n");
142     size = GlobalSize(gbl);
143     ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size);
144 
145     gbl = GlobalReAlloc(gbl, 0, GMEM_MOVEABLE);
146     ok(gbl != NULL, "GlobalReAlloc should not fail on size 0\n");
147 
148     size = GlobalSize(gbl);
149     ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size);
150     ok(GlobalFree(gbl) == NULL, "Memory not freed\n");
151     size = GlobalSize(gbl);
152     ok(size == 0, "Memory should have been freed, size=%ld\n", size);
153 
154     gbl = GlobalReAlloc(0, 10, GMEM_MOVEABLE);
155     ok(gbl == NULL, "global realloc allocated memory\n");
156 
157     /* GlobalLock / GlobalUnlock with a valid handle */
158     gbl = GlobalAlloc(GMEM_MOVEABLE, 256);
159 
160     SetLastError(MAGIC_DEAD);
161     mem = GlobalLock(gbl);      /* #1 */
162     ok(mem != NULL, "returned %p with %d (expected '!= NULL')\n", mem, GetLastError());
163     SetLastError(MAGIC_DEAD);
164     flags = GlobalFlags(gbl);
165     ok( flags == 1, "returned 0x%04x with %d (expected '0x0001')\n",
166         flags, GetLastError());
167 
168     SetLastError(MAGIC_DEAD);
169     msecond = GlobalLock(gbl);   /* #2 */
170     ok( msecond == mem, "returned %p with %d (expected '%p')\n",
171         msecond, GetLastError(), mem);
172     SetLastError(MAGIC_DEAD);
173     flags = GlobalFlags(gbl);
174     ok( flags == 2, "returned 0x%04x with %d (expected '0x0002')\n",
175         flags, GetLastError());
176     SetLastError(MAGIC_DEAD);
177 
178     SetLastError(MAGIC_DEAD);
179     res = GlobalUnlock(gbl);    /* #1 */
180     ok(res, "returned %d with %d (expected '!= 0')\n", res, GetLastError());
181     SetLastError(MAGIC_DEAD);
182     flags = GlobalFlags(gbl);
183     ok( flags , "returned 0x%04x with %d (expected '!= 0')\n",
184         flags, GetLastError());
185 
186     SetLastError(MAGIC_DEAD);
187     res = GlobalUnlock(gbl);    /* #0 */
188     /* NT: ERROR_SUCCESS (documented on MSDN), 9x: untouched */
189     ok(!res && ((GetLastError() == ERROR_SUCCESS) || (GetLastError() == MAGIC_DEAD)),
190         "returned %d with %d (expected '0' with: ERROR_SUCCESS or "
191         "MAGIC_DEAD)\n", res, GetLastError());
192     SetLastError(MAGIC_DEAD);
193     flags = GlobalFlags(gbl);
194     ok( !flags , "returned 0x%04x with %d (expected '0')\n",
195         flags, GetLastError());
196 
197     /* Unlock an already unlocked Handle */
198     SetLastError(MAGIC_DEAD);
199     res = GlobalUnlock(gbl);
200     /* NT: ERROR_NOT_LOCKED,  9x: untouched */
201     ok( !res &&
202         ((GetLastError() == ERROR_NOT_LOCKED) || (GetLastError() == MAGIC_DEAD)),
203         "returned %d with %d (expected '0' with: ERROR_NOT_LOCKED or "
204         "MAGIC_DEAD)\n", res, GetLastError());
205 
206     GlobalFree(gbl);
207     /* invalid handles are caught in windows: */
208     SetLastError(MAGIC_DEAD);
209     hsecond = GlobalFree(gbl);      /* invalid handle: free memory twice */
210     ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE),
211         "returned %p with 0x%08x (expected %p with ERROR_INVALID_HANDLE)\n",
212         hsecond, GetLastError(), gbl);
213     SetLastError(MAGIC_DEAD);
214     flags = GlobalFlags(gbl);
215     ok( (flags == GMEM_INVALID_HANDLE) && (GetLastError() == ERROR_INVALID_HANDLE),
216         "returned 0x%04x with 0x%08x (expected GMEM_INVALID_HANDLE with "
217         "ERROR_INVALID_HANDLE)\n", flags, GetLastError());
218     SetLastError(MAGIC_DEAD);
219     size = GlobalSize(gbl);
220     ok( (size == 0) && (GetLastError() == ERROR_INVALID_HANDLE),
221         "returned %ld with 0x%08x (expected '0' with ERROR_INVALID_HANDLE)\n",
222         size, GetLastError());
223 
224     SetLastError(MAGIC_DEAD);
225     mem = GlobalLock(gbl);
226     ok( (mem == NULL) && (GetLastError() == ERROR_INVALID_HANDLE),
227         "returned %p with 0x%08x (expected NULL with ERROR_INVALID_HANDLE)\n",
228         mem, GetLastError());
229 
230     /* documented on MSDN: GlobalUnlock() return FALSE on failure.
231        Win9x and wine return FALSE with ERROR_INVALID_HANDLE, but on
232        NT 3.51 and XPsp2, TRUE with ERROR_INVALID_HANDLE is returned.
233        The similar Test for LocalUnlock() works on all Systems */
234     SetLastError(MAGIC_DEAD);
235     res = GlobalUnlock(gbl);
236     ok(GetLastError() == ERROR_INVALID_HANDLE,
237         "returned %d with %d (expected ERROR_INVALID_HANDLE)\n",
238         res, GetLastError());
239 
240     gbl = GlobalAlloc(GMEM_DDESHARE, 100);
241 
242     /* first free */
243     mem = GlobalFree(gbl);
244     ok(mem == NULL, "Expected NULL, got %p\n", mem);
245 
246     /* invalid free */
247     if (sizeof(void *) != 8)  /* crashes on 64-bit Vista */
248     {
249         SetLastError(MAGIC_DEAD);
250         mem = GlobalFree(gbl);
251         ok(mem == gbl || broken(mem == NULL) /* nt4 */, "Expected gbl, got %p\n", mem);
252         if (mem == gbl)
253             ok(GetLastError() == ERROR_INVALID_HANDLE ||
254                GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */
255                "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
256     }
257 
258     /* GMEM_FIXED block expands in place only without flags */
259     for (size = 1; size <= max_size; size <<= 1) {
260         gbl = GlobalAlloc(GMEM_FIXED, init_size);
261         SetLastError(MAGIC_DEAD);
262         hsecond = GlobalReAlloc(gbl, size + init_size, 0);
263         ok(hsecond == gbl || (hsecond == NULL && GetLastError() == ERROR_NOT_ENOUGH_MEMORY),
264            "got %p with %x (expected %p or NULL) @%ld\n", hsecond, GetLastError(), gbl, size);
265         GlobalFree(gbl);
266     }
267 
268     /* GMEM_FIXED block can be relocated with GMEM_MOVEABLE */
269     for (size = 1; size <= max_size; size <<= 1) {
270         gbl = GlobalAlloc(GMEM_FIXED, init_size);
271         SetLastError(MAGIC_DEAD);
272         hsecond = GlobalReAlloc(gbl, size + init_size, GMEM_MOVEABLE);
273         ok(hsecond != NULL,
274            "got %p with %x (expected non-NULL) @%ld\n", hsecond, GetLastError(), size);
275         mem = GlobalLock(hsecond);
276         ok(mem == hsecond, "got %p (expected %p) @%ld\n", mem, hsecond, size);
277         GlobalFree(hsecond);
278     }
279 
280     gbl = GlobalAlloc(GMEM_DDESHARE, 100);
281 
282     res = GlobalUnlock(gbl);
283     ok(res == 1 ||
284        broken(res == 0), /* win9x */
285        "Expected 1 or 0, got %d\n", res);
286 
287     res = GlobalUnlock(gbl);
288     ok(res == 1 ||
289        broken(res == 0), /* win9x */
290        "Expected 1 or 0, got %d\n", res);
291 
292     GlobalFree(gbl);
293 
294     gbl = GlobalAlloc(GMEM_FIXED, 100);
295 
296     SetLastError(0xdeadbeef);
297     res = GlobalUnlock(gbl);
298     ok(res == 1 ||
299        broken(res == 0), /* win9x */
300        "Expected 1 or 0, got %d\n", res);
301     ok(GetLastError() == 0xdeadbeef, "got %d\n", GetLastError());
302 
303     GlobalFree(gbl);
304 
305     /* GlobalSize on an invalid handle */
306     if (sizeof(void *) != 8)  /* crashes on 64-bit Vista */
307     {
308         SetLastError(MAGIC_DEAD);
309         size = GlobalSize((HGLOBAL)0xc042);
310         ok(size == 0, "Expected 0, got %ld\n", size);
311         ok(GetLastError() == ERROR_INVALID_HANDLE ||
312            GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */
313            "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
314     }
315 
316     gbl = GlobalAlloc( GMEM_FIXED, 0 );
317     SetLastError(0xdeadbeef);
318     size = GlobalSize( gbl );
319     ok( size == 1, "wrong size %lu\n", size );
320     GlobalFree( gbl );
321 
322     /* ####################################### */
323     /* Local*() functions */
324     gbl = LocalAlloc(LMEM_MOVEABLE, 0);
325     ok(gbl != NULL, "local memory not allocated for size 0\n");
326 
327     gbl = LocalReAlloc(gbl, 10, LMEM_MOVEABLE);
328     ok(gbl != NULL, "Can't realloc local memory\n");
329     size = LocalSize(gbl);
330     ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size);
331 
332     gbl = LocalReAlloc(gbl, 0, LMEM_MOVEABLE);
333     ok(gbl != NULL, "LocalReAlloc should not fail on size 0\n");
334 
335     size = LocalSize(gbl);
336     ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size);
337     ok(LocalFree(gbl) == NULL, "Memory not freed\n");
338     size = LocalSize(gbl);
339     ok(size == 0, "Memory should have been freed, size=%ld\n", size);
340 
341     gbl = LocalReAlloc(0, 10, LMEM_MOVEABLE);
342     ok(gbl == NULL, "local realloc allocated memory\n");
343 
344     /* LocalLock / LocalUnlock with a valid handle */
345     gbl = LocalAlloc(LMEM_MOVEABLE, 256);
346     SetLastError(MAGIC_DEAD);
347     mem = LocalLock(gbl);      /* #1 */
348     ok(mem != NULL, "returned %p with %d (expected '!= NULL')\n", mem, GetLastError());
349     SetLastError(MAGIC_DEAD);
350     flags = LocalFlags(gbl);
351     ok( flags == 1, "returned 0x%04x with %d (expected '0x0001')\n",
352         flags, GetLastError());
353 
354     SetLastError(MAGIC_DEAD);
355     msecond = LocalLock(gbl);   /* #2 */
356     ok( msecond == mem, "returned %p with %d (expected '%p')\n",
357         msecond, GetLastError(), mem);
358     SetLastError(MAGIC_DEAD);
359     flags = LocalFlags(gbl);
360     ok( flags == 2, "returned 0x%04x with %d (expected '0x0002')\n",
361         flags, GetLastError());
362     SetLastError(MAGIC_DEAD);
363 
364     SetLastError(MAGIC_DEAD);
365     res = LocalUnlock(gbl);    /* #1 */
366     ok(res, "returned %d with %d (expected '!= 0')\n", res, GetLastError());
367     SetLastError(MAGIC_DEAD);
368     flags = LocalFlags(gbl);
369     ok( flags , "returned 0x%04x with %d (expected '!= 0')\n",
370         flags, GetLastError());
371 
372     SetLastError(MAGIC_DEAD);
373     res = LocalUnlock(gbl);    /* #0 */
374     /* NT: ERROR_SUCCESS (documented on MSDN), 9x: untouched */
375     ok(!res && ((GetLastError() == ERROR_SUCCESS) || (GetLastError() == MAGIC_DEAD)),
376         "returned %d with %d (expected '0' with: ERROR_SUCCESS or "
377         "MAGIC_DEAD)\n", res, GetLastError());
378     SetLastError(MAGIC_DEAD);
379     flags = LocalFlags(gbl);
380     ok( !flags , "returned 0x%04x with %d (expected '0')\n",
381         flags, GetLastError());
382 
383     /* Unlock an already unlocked Handle */
384     SetLastError(MAGIC_DEAD);
385     res = LocalUnlock(gbl);
386     /* NT: ERROR_NOT_LOCKED,  9x: untouched */
387     ok( !res &&
388         ((GetLastError() == ERROR_NOT_LOCKED) || (GetLastError() == MAGIC_DEAD)),
389         "returned %d with %d (expected '0' with: ERROR_NOT_LOCKED or "
390         "MAGIC_DEAD)\n", res, GetLastError());
391 
392     LocalFree(gbl);
393     /* invalid handles are caught in windows: */
394     SetLastError(MAGIC_DEAD);
395     hsecond = LocalFree(gbl);       /* invalid handle: free memory twice */
396     ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE),
397         "returned %p with 0x%08x (expected %p with ERROR_INVALID_HANDLE)\n",
398         hsecond, GetLastError(), gbl);
399     SetLastError(MAGIC_DEAD);
400     flags = LocalFlags(gbl);
401     ok( (flags == LMEM_INVALID_HANDLE) && (GetLastError() == ERROR_INVALID_HANDLE),
402         "returned 0x%04x with 0x%08x (expected LMEM_INVALID_HANDLE with "
403         "ERROR_INVALID_HANDLE)\n", flags, GetLastError());
404     SetLastError(MAGIC_DEAD);
405     size = LocalSize(gbl);
406     ok( (size == 0) && (GetLastError() == ERROR_INVALID_HANDLE),
407         "returned %ld with 0x%08x (expected '0' with ERROR_INVALID_HANDLE)\n",
408         size, GetLastError());
409 
410     SetLastError(MAGIC_DEAD);
411     mem = LocalLock(gbl);
412     ok( (mem == NULL) && (GetLastError() == ERROR_INVALID_HANDLE),
413         "returned %p with 0x%08x (expected NULL with ERROR_INVALID_HANDLE)\n",
414         mem, GetLastError());
415 
416     /* This Test works the same on all Systems (GlobalUnlock() is different) */
417     SetLastError(MAGIC_DEAD);
418     res = LocalUnlock(gbl);
419     ok(!res && (GetLastError() == ERROR_INVALID_HANDLE),
420         "returned %d with %d (expected '0' with ERROR_INVALID_HANDLE)\n",
421         res, GetLastError());
422 
423     /* LMEM_FIXED block expands in place only without flags */
424     for (size = 1; size <= max_size; size <<= 1) {
425         gbl = LocalAlloc(LMEM_FIXED, init_size);
426         SetLastError(MAGIC_DEAD);
427         hsecond = LocalReAlloc(gbl, size + init_size, 0);
428         ok(hsecond == gbl || (hsecond == NULL && GetLastError() == ERROR_NOT_ENOUGH_MEMORY),
429            "got %p with %x (expected %p or NULL) @%ld\n", hsecond, GetLastError(), gbl, size);
430         LocalFree(gbl);
431     }
432 
433     /* LMEM_FIXED memory can be relocated with LMEM_MOVEABLE */
434     for (size = 1; size <= max_size; size <<= 1) {
435         gbl = LocalAlloc(LMEM_FIXED, init_size);
436         SetLastError(MAGIC_DEAD);
437         hsecond = LocalReAlloc(gbl, size + init_size, LMEM_MOVEABLE);
438         ok(hsecond != NULL,
439            "got %p with %x (expected non-NULL) @%ld\n", hsecond, GetLastError(), size);
440         mem = LocalLock(hsecond);
441         ok(mem == hsecond, "got %p (expected %p) @%ld\n", mem, hsecond, size);
442         LocalFree(hsecond);
443     }
444 
445     /* trying to unlock pointer from LocalAlloc */
446     gbl = LocalAlloc(LMEM_FIXED, 100);
447     SetLastError(0xdeadbeef);
448     res = LocalUnlock(gbl);
449     ok(res == 0, "Expected 0, got %d\n", res);
450     ok(GetLastError() == ERROR_NOT_LOCKED ||
451        broken(GetLastError() == 0xdeadbeef) /* win9x */, "got %d\n", GetLastError());
452     LocalFree(gbl);
453 
454     gbl = LocalAlloc( LMEM_FIXED, 0 );
455     SetLastError(0xdeadbeef);
456     size = LocalSize( gbl );
457     ok( !size || broken(size == 1), /* vistau64 */
458         "wrong size %lu\n", size );
459     LocalFree( gbl );
460 
461     /* trying to lock empty memory should give an error */
462     gbl = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,0);
463     ok(gbl != NULL, "returned NULL\n");
464     SetLastError(MAGIC_DEAD);
465     mem = GlobalLock(gbl);
466     /* NT: ERROR_DISCARDED,  9x: untouched */
467     ok( (mem == NULL) &&
468         ((GetLastError() == ERROR_DISCARDED) || (GetLastError() == MAGIC_DEAD)),
469         "returned %p with 0x%x/%d (expected 'NULL' with: ERROR_DISCARDED or "
470         "MAGIC_DEAD)\n", mem, GetLastError(), GetLastError());
471 
472     GlobalFree(gbl);
473 
474     /* trying to get size from data pointer (GMEM_MOVEABLE) */
475     gbl = GlobalAlloc(GMEM_MOVEABLE, 0x123);
476     ok(gbl != NULL, "returned NULL\n");
477     mem = GlobalLock(gbl);
478     ok(mem != NULL, "returned NULL.\n");
479     ok(gbl != mem, "unexpectedly equal.\n");
480 
481     size = GlobalSize(gbl);
482     size2 = GlobalSize(mem);
483     ok(size == 0x123, "got %lu\n", size);
484     ok(size2 == 0x123, "got %lu\n", size2);
485 
486     GlobalFree(gbl);
487 
488     /* trying to get size from data pointer (GMEM_FIXED) */
489     gbl = GlobalAlloc(GMEM_FIXED, 0x123);
490     ok(gbl != NULL, "returned NULL\n");
491     mem = GlobalLock(gbl);
492     ok(mem != NULL, "returned NULL.\n");
493     ok(gbl == mem, "got %p, %p.\n", gbl, mem);
494 
495     size = GlobalSize(gbl);
496     ok(size == 0x123, "got %lu\n", size);
497 
498     GlobalFree(gbl);
499 
500     size = GlobalSize((void *)0xdeadbee0);
501     ok(size == 0, "got %lu\n", size);
502 
503 }
504 
505 
506 static void test_HeapCreate(void)
507 {
508     SYSTEM_INFO sysInfo;
509     ULONG memchunk;
510     HANDLE heap;
511     LPVOID mem1,mem1a,mem3;
512     UCHAR *mem2,*mem2a;
513     UINT i;
514     BOOL error;
515     DWORD dwSize;
516 
517     /* Retrieve the page size for this system */
518     GetSystemInfo(&sysInfo);
519     ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
520 
521     /* Create a Heap with a minimum and maximum size */
522     /* Note that Windows and Wine seem to behave a bit differently with respect
523        to memory allocation.  In Windows, you can't access all the memory
524        specified in the heap (due to overhead), so choosing a reasonable maximum
525        size for the heap was done mostly by trial-and-error on Win2k.  It may need
526        more tweaking for otherWindows variants.
527     */
528     memchunk=10*sysInfo.dwPageSize;
529     heap=HeapCreate(0,2*memchunk,5*memchunk);
530     ok( !((ULONG_PTR)heap & 0xffff), "heap %p not 64K aligned\n", heap );
531 
532     /* Check that HeapCreate allocated the right amount of ram */
533     mem1=HeapAlloc(heap,0,5*memchunk+1);
534     ok(mem1==NULL,"HeapCreate allocated more Ram than it should have\n");
535     HeapFree(heap,0,mem1);
536 
537     /* Check that a normal alloc works */
538     mem1=HeapAlloc(heap,0,memchunk);
539     ok(mem1!=NULL,"HeapAlloc failed\n");
540     if(mem1) {
541       ok(HeapSize(heap,0,mem1)>=memchunk, "HeapAlloc should return a big enough memory block\n");
542     }
543 
544     /* Check that a 'zeroing' alloc works */
545     mem2=HeapAlloc(heap,HEAP_ZERO_MEMORY,memchunk);
546     ok(mem2!=NULL,"HeapAlloc failed\n");
547     if(mem2) {
548       ok(HeapSize(heap,0,mem2)>=memchunk,"HeapAlloc should return a big enough memory block\n");
549       error=FALSE;
550       for(i=0;i<memchunk;i++) {
551         if(mem2[i]!=0) {
552           error=TRUE;
553         }
554       }
555       ok(!error,"HeapAlloc should have zeroed out its allocated memory\n");
556     }
557 
558     /* Check that HeapAlloc returns NULL when requested way too much memory */
559     mem3=HeapAlloc(heap,0,5*memchunk);
560     ok(mem3==NULL,"HeapAlloc should return NULL\n");
561     if(mem3) {
562       ok(HeapFree(heap,0,mem3),"HeapFree didn't pass successfully\n");
563     }
564 
565     /* Check that HeapRealloc works */
566     mem2a=HeapReAlloc(heap,HEAP_ZERO_MEMORY,mem2,memchunk+5*sysInfo.dwPageSize);
567     ok(mem2a!=NULL,"HeapReAlloc failed\n");
568     if(mem2a) {
569       ok(HeapSize(heap,0,mem2a)>=memchunk+5*sysInfo.dwPageSize,"HeapReAlloc failed\n");
570       error=FALSE;
571       for(i=0;i<5*sysInfo.dwPageSize;i++) {
572         if(mem2a[memchunk+i]!=0) {
573           error=TRUE;
574         }
575       }
576       ok(!error,"HeapReAlloc should have zeroed out its allocated memory\n");
577     }
578 
579     /* Check that HeapRealloc honours HEAP_REALLOC_IN_PLACE_ONLY */
580     error=FALSE;
581     mem1a=HeapReAlloc(heap,HEAP_REALLOC_IN_PLACE_ONLY,mem1,memchunk+sysInfo.dwPageSize);
582     if(mem1a!=NULL) {
583       if(mem1a!=mem1) {
584         error=TRUE;
585       }
586     }
587     ok(mem1a==NULL || !error,"HeapReAlloc didn't honour HEAP_REALLOC_IN_PLACE_ONLY\n");
588 
589     /* Check that HeapFree works correctly */
590    if(mem1a) {
591      ok(HeapFree(heap,0,mem1a),"HeapFree failed\n");
592    } else {
593      ok(HeapFree(heap,0,mem1),"HeapFree failed\n");
594    }
595    if(mem2a) {
596      ok(HeapFree(heap,0,mem2a),"HeapFree failed\n");
597    } else {
598      ok(HeapFree(heap,0,mem2),"HeapFree failed\n");
599    }
600 
601    /* 0-length buffer */
602    mem1 = HeapAlloc(heap, 0, 0);
603    ok(mem1 != NULL, "Reserved memory\n");
604 
605    dwSize = HeapSize(heap, 0, mem1);
606    /* should work with 0-length buffer */
607    ok(dwSize < 0xFFFFFFFF, "The size of the 0-length buffer\n");
608    ok(HeapFree(heap, 0, mem1), "Freed the 0-length buffer\n");
609 
610    /* Check that HeapDestroy works */
611    ok(HeapDestroy(heap),"HeapDestroy failed\n");
612 }
613 
614 
615 static void test_GlobalAlloc(void)
616 {
617     ULONG memchunk;
618     HGLOBAL mem1,mem2,mem2a,mem2b;
619     UCHAR *mem2ptr;
620     UINT i;
621     BOOL error;
622     memchunk=100000;
623 
624     SetLastError(NO_ERROR);
625     /* Check that a normal alloc works */
626     mem1=GlobalAlloc(0,memchunk);
627     ok(mem1!=NULL,"GlobalAlloc failed\n");
628     if(mem1) {
629       ok(GlobalSize(mem1)>=memchunk, "GlobalAlloc should return a big enough memory block\n");
630     }
631 
632     /* Check that a 'zeroing' alloc works */
633     mem2=GlobalAlloc(GMEM_ZEROINIT,memchunk);
634     ok(mem2!=NULL,"GlobalAlloc failed: error=%d\n",GetLastError());
635     if(mem2) {
636       ok(GlobalSize(mem2)>=memchunk,"GlobalAlloc should return a big enough memory block\n");
637       mem2ptr=GlobalLock(mem2);
638       ok(mem2ptr==mem2,"GlobalLock should have returned the same memory as was allocated\n");
639       if(mem2ptr) {
640         error=FALSE;
641         for(i=0;i<memchunk;i++) {
642           if(mem2ptr[i]!=0) {
643             error=TRUE;
644           }
645         }
646         ok(!error,"GlobalAlloc should have zeroed out its allocated memory\n");
647       }
648    }
649     /* Check that GlobalReAlloc works */
650     /* Check that we can change GMEM_FIXED to GMEM_MOVEABLE */
651     mem2a=GlobalReAlloc(mem2,0,GMEM_MODIFY | GMEM_MOVEABLE);
652     if(mem2a!=NULL) {
653       mem2=mem2a;
654       mem2ptr=GlobalLock(mem2a);
655       ok(mem2ptr!=NULL && !GlobalUnlock(mem2a)&&GetLastError()==NO_ERROR,
656          "Converting from FIXED to MOVEABLE didn't REALLY work\n");
657     }
658 
659     /* Check that ReAllocing memory works as expected */
660     mem2a=GlobalReAlloc(mem2,2*memchunk,GMEM_MOVEABLE | GMEM_ZEROINIT);
661     ok(mem2a!=NULL,"GlobalReAlloc failed\n");
662     if(mem2a) {
663       ok(GlobalSize(mem2a)>=2*memchunk,"GlobalReAlloc failed\n");
664       mem2ptr=GlobalLock(mem2a);
665       ok(mem2ptr!=NULL,"GlobalLock Failed\n");
666       if(mem2ptr) {
667         error=FALSE;
668         for(i=0;i<memchunk;i++) {
669           if(mem2ptr[memchunk+i]!=0) {
670             error=TRUE;
671           }
672         }
673         ok(!error,"GlobalReAlloc should have zeroed out its allocated memory\n");
674 
675         /* Check that GlobalHandle works */
676         mem2b=GlobalHandle(mem2ptr);
677         ok(mem2b==mem2a,"GlobalHandle didn't return the correct memory handle %p/%p for %p\n",
678            mem2a, mem2b, mem2ptr);
679         /* Check that we can't discard locked memory */
680         mem2b=GlobalDiscard(mem2a);
681         if(mem2b==NULL) {
682           ok(!GlobalUnlock(mem2a) && GetLastError()==NO_ERROR,"GlobalUnlock Failed\n");
683         }
684       }
685     }
686     if(mem1) {
687       ok(GlobalFree(mem1)==NULL,"GlobalFree failed\n");
688     }
689     if(mem2a) {
690       ok(GlobalFree(mem2a)==NULL,"GlobalFree failed\n");
691     } else {
692       ok(GlobalFree(mem2)==NULL,"GlobalFree failed\n");
693     }
694 }
695 
696 
697 static void test_LocalAlloc(void)
698 {
699     ULONG memchunk;
700     HLOCAL mem1,mem2,mem2a,mem2b;
701     UCHAR *mem2ptr;
702     UINT i;
703     BOOL error;
704     memchunk=100000;
705 
706     /* Check that a normal alloc works */
707     mem1=LocalAlloc(0,memchunk);
708     ok(mem1!=NULL,"LocalAlloc failed: error=%d\n",GetLastError());
709     if(mem1) {
710       ok(LocalSize(mem1)>=memchunk, "LocalAlloc should return a big enough memory block\n");
711     }
712 
713     /* Check that a 'zeroing' and lock alloc works */
714     mem2=LocalAlloc(LMEM_ZEROINIT|LMEM_MOVEABLE,memchunk);
715     ok(mem2!=NULL,"LocalAlloc failed: error=%d\n",GetLastError());
716     if(mem2) {
717       ok(LocalSize(mem2)>=memchunk,"LocalAlloc should return a big enough memory block\n");
718       mem2ptr=LocalLock(mem2);
719       ok(mem2ptr!=NULL,"LocalLock: error=%d\n",GetLastError());
720       if(mem2ptr) {
721         error=FALSE;
722         for(i=0;i<memchunk;i++) {
723           if(mem2ptr[i]!=0) {
724             error=TRUE;
725           }
726         }
727         ok(!error,"LocalAlloc should have zeroed out its allocated memory\n");
728         SetLastError(0);
729         error=LocalUnlock(mem2);
730         ok(!error && GetLastError()==NO_ERROR,
731            "LocalUnlock Failed: rc=%d err=%d\n",error,GetLastError());
732       }
733     }
734    mem2a=LocalFree(mem2);
735    ok(mem2a==NULL, "LocalFree failed: %p\n",mem2a);
736 
737    /* Reallocate mem2 as moveable memory */
738    mem2=LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,memchunk);
739    ok(mem2!=NULL, "LocalAlloc failed to create moveable memory, error=%d\n",GetLastError());
740 
741    /* Check that ReAllocing memory works as expected */
742     mem2a=LocalReAlloc(mem2,2*memchunk,LMEM_MOVEABLE | LMEM_ZEROINIT);
743     ok(mem2a!=NULL,"LocalReAlloc failed, error=%d\n",GetLastError());
744     if(mem2a) {
745       ok(LocalSize(mem2a)>=2*memchunk,"LocalReAlloc failed\n");
746       mem2ptr=LocalLock(mem2a);
747       ok(mem2ptr!=NULL,"LocalLock Failed\n");
748       if(mem2ptr) {
749         error=FALSE;
750         for(i=0;i<memchunk;i++) {
751           if(mem2ptr[memchunk+i]!=0) {
752             error=TRUE;
753           }
754         }
755         ok(!error,"LocalReAlloc should have zeroed out its allocated memory\n");
756         /* Check that LocalHandle works */
757         mem2b=LocalHandle(mem2ptr);
758         ok(mem2b==mem2a,"LocalHandle didn't return the correct memory handle %p/%p for %p\n",
759            mem2a, mem2b, mem2ptr);
760         /* Check that we can't discard locked memory */
761         mem2b=LocalDiscard(mem2a);
762         ok(mem2b==NULL,"Discarded memory we shouldn't have\n");
763         SetLastError(NO_ERROR);
764         ok(!LocalUnlock(mem2a) && GetLastError()==NO_ERROR, "LocalUnlock Failed\n");
765       }
766     }
767     if(mem1) {
768       ok(LocalFree(mem1)==NULL,"LocalFree failed\n");
769     }
770     if(mem2a) {
771       ok(LocalFree(mem2a)==NULL,"LocalFree failed\n");
772     } else {
773       ok(LocalFree(mem2)==NULL,"LocalFree failed\n");
774     }
775 }
776 
777 static void test_obsolete_flags(void)
778 {
779     static struct {
780         UINT flags;
781         UINT globalflags;
782     } test_global_flags[] = {
783         {GMEM_FIXED | GMEM_NOTIFY, 0},
784         {GMEM_FIXED | GMEM_DISCARDABLE, 0},
785         {GMEM_MOVEABLE | GMEM_NOTIFY, 0},
786         {GMEM_MOVEABLE | GMEM_DDESHARE, GMEM_DDESHARE},
787         {GMEM_MOVEABLE | GMEM_NOT_BANKED, 0},
788         {GMEM_MOVEABLE | GMEM_NODISCARD, 0},
789         {GMEM_MOVEABLE | GMEM_DISCARDABLE, GMEM_DISCARDABLE},
790         {GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_DISCARDABLE | GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NODISCARD |
791          GMEM_NOT_BANKED | GMEM_NOTIFY, GMEM_DDESHARE | GMEM_DISCARDABLE},
792     };
793 
794     unsigned int i;
795     HGLOBAL gbl;
796     UINT resultflags;
797 
798     UINT (WINAPI *pGlobalFlags)(HGLOBAL);
799 
800     pGlobalFlags = (void *) GetProcAddress(GetModuleHandleA("kernel32"), "GlobalFlags");
801 
802     if (!pGlobalFlags)
803     {
804         win_skip("GlobalFlags is not available\n");
805         return;
806     }
807 
808     for (i = 0; i < sizeof(test_global_flags)/sizeof(test_global_flags[0]); i++)
809     {
810         gbl = GlobalAlloc(test_global_flags[i].flags, 4);
811         ok(gbl != NULL, "GlobalAlloc failed\n");
812 
813         SetLastError(MAGIC_DEAD);
814         resultflags = pGlobalFlags(gbl);
815 
816         ok( resultflags == test_global_flags[i].globalflags ||
817             broken(resultflags == (test_global_flags[i].globalflags & ~GMEM_DDESHARE)), /* win9x */
818             "%u: expected 0x%08x, but returned 0x%08x with %d\n",
819             i, test_global_flags[i].globalflags, resultflags, GetLastError() );
820 
821         GlobalFree(gbl);
822     }
823 }
824 
825 static void test_HeapQueryInformation(void)
826 {
827     ULONG info;
828     SIZE_T size;
829     BOOL ret;
830 
831     pHeapQueryInformation = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "HeapQueryInformation");
832     if (!pHeapQueryInformation)
833     {
834         win_skip("HeapQueryInformation is not available\n");
835         return;
836     }
837 
838     if (0) /* crashes under XP */
839     {
840         size = 0;
841         pHeapQueryInformation(0,
842                                 HeapCompatibilityInformation,
843                                 &info, sizeof(info), &size);
844         size = 0;
845         pHeapQueryInformation(GetProcessHeap(),
846                                 HeapCompatibilityInformation,
847                                 NULL, sizeof(info), &size);
848     }
849 
850     size = 0;
851     SetLastError(0xdeadbeef);
852     ret = pHeapQueryInformation(GetProcessHeap(),
853                                 HeapCompatibilityInformation,
854                                 NULL, 0, &size);
855     ok(!ret, "HeapQueryInformation should fail\n");
856     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
857        "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError());
858     ok(size == sizeof(ULONG), "expected 4, got %lu\n", size);
859 
860     SetLastError(0xdeadbeef);
861     ret = pHeapQueryInformation(GetProcessHeap(),
862                                 HeapCompatibilityInformation,
863                                 NULL, 0, NULL);
864     ok(!ret, "HeapQueryInformation should fail\n");
865     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
866        "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError());
867 
868     info = 0xdeadbeaf;
869     SetLastError(0xdeadbeef);
870     ret = pHeapQueryInformation(GetProcessHeap(),
871                                 HeapCompatibilityInformation,
872                                 &info, sizeof(info) + 1, NULL);
873     ok(ret, "HeapQueryInformation error %u\n", GetLastError());
874     ok(info == 0 || info == 1 || info == 2, "expected 0, 1 or 2, got %u\n", info);
875 }
876 
877 static void test_heap_checks( DWORD flags )
878 {
879     BYTE old, *p, *p2;
880     BOOL ret;
881     SIZE_T i, size, large_size = 3000 * 1024 + 37;
882 
883     if (flags & HEAP_PAGE_ALLOCS) return;  /* no tests for that case yet */
884     trace( "testing heap flags %08x\n", flags );
885 
886     p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 17 );
887     ok( p != NULL, "HeapAlloc failed\n" );
888 
889     ret = HeapValidate( GetProcessHeap(), 0, p );
890     ok( ret, "HeapValidate failed\n" );
891 
892     size = HeapSize( GetProcessHeap(), 0, p );
893     ok( size == 17, "Wrong size %lu\n", size );
894 
895     ok( p[14] == 0, "wrong data %x\n", p[14] );
896     ok( p[15] == 0, "wrong data %x\n", p[15] );
897     ok( p[16] == 0, "wrong data %x\n", p[16] );
898 
899     if (flags & HEAP_TAIL_CHECKING_ENABLED)
900     {
901         ok( p[17] == 0xab, "wrong padding %x\n", p[17] );
902         ok( p[18] == 0xab, "wrong padding %x\n", p[18] );
903         ok( p[19] == 0xab, "wrong padding %x\n", p[19] );
904     }
905 
906     p2 = HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, p, 14 );
907     if (p2 == p)
908     {
909         if (flags & HEAP_TAIL_CHECKING_ENABLED)
910         {
911             ok( p[14] == 0xab, "wrong padding %x\n", p[14] );
912             ok( p[15] == 0xab, "wrong padding %x\n", p[15] );
913             ok( p[16] == 0xab, "wrong padding %x\n", p[16] );
914         }
915         else
916         {
917             ok( p[14] == 0, "wrong padding %x\n", p[14] );
918             ok( p[15] == 0, "wrong padding %x\n", p[15] );
919         }
920     }
921     else skip( "realloc in place failed\n");
922 
923     ret = HeapFree( GetProcessHeap(), 0, p );
924     ok( ret, "HeapFree failed\n" );
925 
926     p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 17 );
927     ok( p != NULL, "HeapAlloc failed\n" );
928     old = p[17];
929     p[17] = 0xcc;
930 
931     if (flags & HEAP_TAIL_CHECKING_ENABLED)
932     {
933         ret = HeapValidate( GetProcessHeap(), 0, p );
934         ok( !ret, "HeapValidate succeeded\n" );
935 
936         /* other calls only check when HEAP_VALIDATE is set */
937         if (flags & HEAP_VALIDATE)
938         {
939             size = HeapSize( GetProcessHeap(), 0, p );
940             ok( size == ~(SIZE_T)0 || broken(size == ~0u), "Wrong size %lu\n", size );
941 
942             p2 = HeapReAlloc( GetProcessHeap(), 0, p, 14 );
943             ok( p2 == NULL, "HeapReAlloc succeeded\n" );
944 
945             ret = HeapFree( GetProcessHeap(), 0, p );
946             ok( !ret || broken(sizeof(void*) == 8), /* not caught on xp64 */
947                 "HeapFree succeeded\n" );
948         }
949 
950         p[17] = old;
951         size = HeapSize( GetProcessHeap(), 0, p );
952         ok( size == 17, "Wrong size %lu\n", size );
953 
954         p2 = HeapReAlloc( GetProcessHeap(), 0, p, 14 );
955         ok( p2 != NULL, "HeapReAlloc failed\n" );
956         p = p2;
957     }
958 
959     ret = HeapFree( GetProcessHeap(), 0, p );
960     ok( ret, "HeapFree failed\n" );
961 
962     p = HeapAlloc( GetProcessHeap(), 0, 37 );
963     ok( p != NULL, "HeapAlloc failed\n" );
964     memset( p, 0xcc, 37 );
965 
966     ret = HeapFree( GetProcessHeap(), 0, p );
967     ok( ret, "HeapFree failed\n" );
968 
969     if (flags & HEAP_FREE_CHECKING_ENABLED)
970     {
971         ok( p[16] == 0xee, "wrong data %x\n", p[16] );
972         ok( p[17] == 0xfe, "wrong data %x\n", p[17] );
973         ok( p[18] == 0xee, "wrong data %x\n", p[18] );
974         ok( p[19] == 0xfe, "wrong data %x\n", p[19] );
975 
976         ret = HeapValidate( GetProcessHeap(), 0, NULL );
977         ok( ret, "HeapValidate failed\n" );
978 
979         old = p[16];
980         p[16] = 0xcc;
981         ret = HeapValidate( GetProcessHeap(), 0, NULL );
982         ok( !ret, "HeapValidate succeeded\n" );
983 
984         p[16] = old;
985         ret = HeapValidate( GetProcessHeap(), 0, NULL );
986         ok( ret, "HeapValidate failed\n" );
987     }
988 
989     /* now test large blocks */
990 
991     p = HeapAlloc( GetProcessHeap(), 0, large_size );
992     ok( p != NULL, "HeapAlloc failed\n" );
993 
994     ret = HeapValidate( GetProcessHeap(), 0, p );
995     ok( ret, "HeapValidate failed\n" );
996 
997     size = HeapSize( GetProcessHeap(), 0, p );
998     ok( size == large_size, "Wrong size %lu\n", size );
999 
1000     ok( p[large_size - 2] == 0, "wrong data %x\n", p[large_size - 2] );
1001     ok( p[large_size - 1] == 0, "wrong data %x\n", p[large_size - 1] );
1002 
1003     if (flags & HEAP_TAIL_CHECKING_ENABLED)
1004     {
1005         /* Windows doesn't do tail checking on large blocks */
1006         ok( p[large_size] == 0xab || broken(p[large_size] == 0), "wrong data %x\n", p[large_size] );
1007         ok( p[large_size+1] == 0xab || broken(p[large_size+1] == 0), "wrong data %x\n", p[large_size+1] );
1008         ok( p[large_size+2] == 0xab || broken(p[large_size+2] == 0), "wrong data %x\n", p[large_size+2] );
1009         if (p[large_size] == 0xab)
1010         {
1011             p[large_size] = 0xcc;
1012             ret = HeapValidate( GetProcessHeap(), 0, p );
1013             ok( !ret, "HeapValidate succeeded\n" );
1014 
1015             /* other calls only check when HEAP_VALIDATE is set */
1016             if (flags & HEAP_VALIDATE)
1017             {
1018                 size = HeapSize( GetProcessHeap(), 0, p );
1019                 ok( size == ~(SIZE_T)0, "Wrong size %lu\n", size );
1020 
1021                 p2 = HeapReAlloc( GetProcessHeap(), 0, p, large_size - 3 );
1022                 ok( p2 == NULL, "HeapReAlloc succeeded\n" );
1023 
1024                 ret = HeapFree( GetProcessHeap(), 0, p );
1025                 ok( !ret, "HeapFree succeeded\n" );
1026             }
1027             p[large_size] = 0xab;
1028         }
1029     }
1030 
1031     ret = HeapFree( GetProcessHeap(), 0, p );
1032     ok( ret, "HeapFree failed\n" );
1033 
1034     /* test block sizes when tail checking */
1035     if (flags & HEAP_TAIL_CHECKING_ENABLED)
1036     {
1037         for (size = 0; size < 64; size++)
1038         {
1039             p = HeapAlloc( GetProcessHeap(), 0, size );
1040             for (i = 0; i < 32; i++) if (p[size + i] != 0xab) break;
1041             ok( i >= 8, "only %lu tail bytes for size %lu\n", i, size );
1042             HeapFree( GetProcessHeap(), 0, p );
1043         }
1044     }
1045 }
1046 
1047 static void test_debug_heap( const char *argv0, DWORD flags )
1048 {
1049     char keyname[MAX_PATH];
1050     char buffer[MAX_PATH];
1051     PROCESS_INFORMATION	info;
1052     STARTUPINFOA startup;
1053     BOOL ret;
1054     DWORD err;
1055     HKEY hkey;
1056     const char *basename;
1057 
1058     if ((basename = strrchr( argv0, '\\' ))) basename++;
1059     else basename = argv0;
1060 
1061     sprintf( keyname, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s",
1062              basename );
1063     if (!strcmp( keyname + strlen(keyname) - 3, ".so" )) keyname[strlen(keyname) - 3] = 0;
1064 
1065     err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyname, &hkey );
1066     if (err == ERROR_ACCESS_DENIED)
1067     {
1068         skip("Not authorized to change the image file execution options\n");
1069         return;
1070     }
1071     ok( !err, "failed to create '%s' error %u\n", keyname, err );
1072     if (err) return;
1073 
1074     if (flags == 0xdeadbeef)  /* magic value for unsetting it */
1075         RegDeleteValueA( hkey, "GlobalFlag" );
1076     else
1077         RegSetValueExA( hkey, "GlobalFlag", 0, REG_DWORD, (BYTE *)&flags, sizeof(flags) );
1078 
1079     memset( &startup, 0, sizeof(startup) );
1080     startup.cb = sizeof(startup);
1081 
1082     sprintf( buffer, "%s heap.c 0x%x", argv0, flags );
1083     ret = CreateProcessA( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info );
1084     ok( ret, "failed to create child process error %u\n", GetLastError() );
1085     if (ret)
1086     {
1087         winetest_wait_child_process( info.hProcess );
1088         CloseHandle( info.hThread );
1089         CloseHandle( info.hProcess );
1090     }
1091     RegDeleteValueA( hkey, "GlobalFlag" );
1092     RegCloseKey( hkey );
1093     RegDeleteKeyA( HKEY_LOCAL_MACHINE, keyname );
1094 }
1095 
1096 static DWORD heap_flags_from_global_flag( DWORD flag )
1097 {
1098     DWORD ret = 0;
1099 
1100     if (flag & FLG_HEAP_ENABLE_TAIL_CHECK)
1101         ret |= HEAP_TAIL_CHECKING_ENABLED;
1102     if (flag & FLG_HEAP_ENABLE_FREE_CHECK)
1103         ret |= HEAP_FREE_CHECKING_ENABLED;
1104     if (flag & FLG_HEAP_VALIDATE_PARAMETERS)
1105         ret |= HEAP_VALIDATE_PARAMS | HEAP_VALIDATE | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED;
1106     if (flag & FLG_HEAP_VALIDATE_ALL)
1107         ret |= HEAP_VALIDATE_ALL | HEAP_VALIDATE | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED;
1108     if (flag & FLG_HEAP_DISABLE_COALESCING)
1109         ret |= HEAP_DISABLE_COALESCE_ON_FREE;
1110     if (flag & FLG_HEAP_PAGE_ALLOCS)
1111         ret |= HEAP_PAGE_ALLOCS | HEAP_GROWABLE;
1112     return ret;
1113 }
1114 
1115 static void test_child_heap( const char *arg )
1116 {
1117     struct heap_layout *heap = GetProcessHeap();
1118     DWORD expected = strtoul( arg, 0, 16 );
1119     DWORD expect_heap;
1120 
1121     if (expected == 0xdeadbeef)  /* expected value comes from Session Manager global flags */
1122     {
1123         HKEY hkey;
1124         expected = 0;
1125         if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager", &hkey ))
1126         {
1127             char buffer[32];
1128             DWORD type, size = sizeof(buffer);
1129 
1130             if (!RegQueryValueExA( hkey, "GlobalFlag", 0, &type, (BYTE *)buffer, &size ))
1131             {
1132                 if (type == REG_DWORD) expected = *(DWORD *)buffer;
1133                 else if (type == REG_SZ) expected = strtoul( buffer, 0, 16 );
1134             }
1135             RegCloseKey( hkey );
1136         }
1137     }
1138     if (expected && !pRtlGetNtGlobalFlags())  /* not working on NT4 */
1139     {
1140         win_skip( "global flags not set\n" );
1141         return;
1142     }
1143 
1144     ok( pRtlGetNtGlobalFlags() == expected,
1145         "%s: got global flags %08x expected %08x\n", arg, pRtlGetNtGlobalFlags(), expected );
1146 
1147     expect_heap = heap_flags_from_global_flag( expected );
1148 
1149     if (!(heap->flags & HEAP_GROWABLE) || heap->pattern == 0xffeeffee)  /* vista layout */
1150     {
1151         ok( (heap->flags & ~HEAP_GROWABLE) == 0, "%s: got heap flags %08x\n", arg, heap->flags );
1152     }
1153     else if (heap->pattern == 0xeeeeeeee && heap->flags == 0xeeeeeeee)
1154     {
1155         ok( expected & FLG_HEAP_PAGE_ALLOCS, "%s: got heap flags 0xeeeeeeee without page alloc\n", arg );
1156     }
1157     else
1158     {
1159         ok( heap->flags == (expect_heap | HEAP_GROWABLE),
1160             "%s: got heap flags %08x expected %08x\n", arg, heap->flags, expect_heap );
1161         ok( heap->force_flags == (expect_heap & ~0x18000080),
1162             "%s: got heap force flags %08x expected %08x\n", arg, heap->force_flags, expect_heap );
1163         expect_heap = heap->flags;
1164     }
1165 
1166     test_heap_checks( expect_heap );
1167 }
1168 
1169 static void test_GetPhysicallyInstalledSystemMemory(void)
1170 {
1171     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1172     MEMORYSTATUSEX memstatus;
1173     ULONGLONG total_memory;
1174     BOOL ret;
1175 
1176     pGetPhysicallyInstalledSystemMemory = (void *)GetProcAddress(kernel32, "GetPhysicallyInstalledSystemMemory");
1177     if (!pGetPhysicallyInstalledSystemMemory)
1178     {
1179         win_skip("GetPhysicallyInstalledSystemMemory is not available\n");
1180         return;
1181     }
1182 
1183     SetLastError(0xdeadbeef);
1184     ret = pGetPhysicallyInstalledSystemMemory(NULL);
1185     ok(!ret, "GetPhysicallyInstalledSystemMemory should fail\n");
1186     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1187        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1188 
1189     total_memory = 0;
1190     ret = pGetPhysicallyInstalledSystemMemory(&total_memory);
1191     ok(ret, "GetPhysicallyInstalledSystemMemory unexpectedly failed\n");
1192     ok(total_memory != 0, "expected total_memory != 0\n");
1193 
1194     memstatus.dwLength = sizeof(memstatus);
1195     ret = GlobalMemoryStatusEx(&memstatus);
1196     ok(ret, "GlobalMemoryStatusEx unexpectedly failed\n");
1197     ok(total_memory >= memstatus.ullTotalPhys / 1024,
1198        "expected total_memory >= memstatus.ullTotalPhys / 1024\n");
1199 }
1200 
1201 START_TEST(heap)
1202 {
1203     int argc;
1204     char **argv;
1205 
1206     pRtlGetNtGlobalFlags = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlGetNtGlobalFlags" );
1207 
1208     argc = winetest_get_mainargs( &argv );
1209     if (argc >= 3)
1210     {
1211         test_child_heap( argv[2] );
1212         return;
1213     }
1214 
1215     test_heap();
1216     test_obsolete_flags();
1217     test_HeapCreate();
1218     test_GlobalAlloc();
1219     test_LocalAlloc();
1220 
1221     /* Test both short and very long blocks */
1222     test_sized_HeapAlloc(1);
1223     test_sized_HeapAlloc(1 << 20);
1224     test_sized_HeapReAlloc(1, 100);
1225     test_sized_HeapReAlloc(1, (1 << 20));
1226     test_sized_HeapReAlloc((1 << 20), (2 << 20));
1227     test_sized_HeapReAlloc((1 << 20), 1);
1228 
1229     test_HeapQueryInformation();
1230     test_GetPhysicallyInstalledSystemMemory();
1231 
1232     if (pRtlGetNtGlobalFlags)
1233     {
1234         test_debug_heap( argv[0], 0 );
1235         test_debug_heap( argv[0], FLG_HEAP_ENABLE_TAIL_CHECK );
1236         test_debug_heap( argv[0], FLG_HEAP_ENABLE_FREE_CHECK );
1237         test_debug_heap( argv[0], FLG_HEAP_VALIDATE_PARAMETERS );
1238         test_debug_heap( argv[0], FLG_HEAP_VALIDATE_ALL );
1239         test_debug_heap( argv[0], FLG_POOL_ENABLE_TAGGING );
1240         test_debug_heap( argv[0], FLG_HEAP_ENABLE_TAGGING );
1241         test_debug_heap( argv[0], FLG_HEAP_ENABLE_TAG_BY_DLL );
1242         test_debug_heap( argv[0], FLG_HEAP_DISABLE_COALESCING );
1243         test_debug_heap( argv[0], FLG_HEAP_PAGE_ALLOCS );
1244         test_debug_heap( argv[0], 0xdeadbeef );
1245     }
1246     else win_skip( "RtlGetNtGlobalFlags not found, skipping heap debug tests\n" );
1247 }
1248