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