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