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