Improved csrss (doesn't crash any more)
[reactos.git] / reactos / lib / ntdll / rtl / heap.c
1 /*
2 * Win32 heap functions
3 *
4 * Copyright 1996 Alexandre Julliard
5 * Copyright 1998 Ulrich Weigand
6 */
7
8 #include <string.h>
9 #include <ddk/ntddk.h>
10 #include <ntdll/rtl.h>
11
12 #define NDEBUG
13 #include <ntdll/ntdll.h>
14
15 /* Note: the heap data structures are based on what Pietrek describes in his
16 * book 'Windows 95 System Programming Secrets'. The layout is not exactly
17 * the same, but could be easily adapted if it turns out some programs
18 * require it.
19 */
20
21 typedef struct tagARENA_INUSE
22 {
23 DWORD size; /* Block size; must be the first field */
24 WORD threadId; /* Allocating thread id */
25 WORD magic; /* Magic number */
26 DWORD callerEIP; /* EIP of caller upon allocation */
27 } ARENA_INUSE;
28
29 typedef struct tagARENA_FREE
30 {
31 DWORD size; /* Block size; must be the first field */
32 WORD threadId; /* Freeing thread id */
33 WORD magic; /* Magic number */
34 struct tagARENA_FREE *next; /* Next free arena */
35 struct tagARENA_FREE *prev; /* Prev free arena */
36 } ARENA_FREE;
37
38 #define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */
39 #define ARENA_FLAG_PREV_FREE 0x00000002
40 #define ARENA_SIZE_MASK 0xfffffffc
41 #define ARENA_INUSE_MAGIC 0x4842 /* Value for arena 'magic' field */
42 #define ARENA_FREE_MAGIC 0x4846 /* Value for arena 'magic' field */
43
44 #define ARENA_INUSE_FILLER 0x55
45 #define ARENA_FREE_FILLER 0xaa
46
47 #define HEAP_NB_FREE_LISTS 4 /* Number of free lists */
48
49 /* Max size of the blocks on the free lists */
50 static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
51 {
52 0x20, 0x80, 0x200, 0xffffffff
53 };
54
55 typedef struct
56 {
57 DWORD size;
58 ARENA_FREE arena;
59 } FREE_LIST_ENTRY;
60
61 struct tagHEAP;
62
63 typedef struct tagSUBHEAP
64 {
65 DWORD size; /* Size of the whole sub-heap */
66 DWORD commitSize; /* Committed size of the sub-heap */
67 DWORD headerSize; /* Size of the heap header */
68 struct tagSUBHEAP *next; /* Next sub-heap */
69 struct tagHEAP *heap; /* Main heap structure */
70 DWORD magic; /* Magic number */
71 WORD selector; /* Selector for HEAP_WINE_SEGPTR heaps */
72 } SUBHEAP;
73
74 #define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
75
76 typedef struct tagHEAP
77 {
78 SUBHEAP subheap; /* First sub-heap */
79 struct tagHEAP *next; /* Next heap for this process */
80 FREE_LIST_ENTRY freeList[HEAP_NB_FREE_LISTS]; /* Free lists */
81 CRITICAL_SECTION critSection; /* Critical section for serialization */
82 DWORD flags; /* Heap flags */
83 DWORD magic; /* Magic number */
84 } HEAP;
85
86 #define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
87
88 #define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
89 #define HEAP_MIN_BLOCK_SIZE (8+sizeof(ARENA_FREE)) /* Min. heap block size */
90
91
92 /***********************************************************************
93 * HEAP_Dump
94 */
95 void HEAP_Dump( HEAP *heap )
96 {
97 int i;
98 SUBHEAP *subheap;
99 char *ptr;
100
101 DPRINT( "Heap: %08lx\n", (DWORD)heap );
102 DPRINT( "Next: %08lx Sub-heaps: %08lx",
103 (DWORD)heap->next, (DWORD)&heap->subheap );
104 subheap = &heap->subheap;
105 while (subheap->next)
106 {
107 DPRINT( " -> %08lx", (DWORD)subheap->next );
108 subheap = subheap->next;
109 }
110
111 DPRINT( "\nFree lists:\n Block Stat Size Id\n" );
112 for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
113 DPRINT( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
114 (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
115 heap->freeList[i].arena.threadId,
116 (DWORD)heap->freeList[i].arena.prev,
117 (DWORD)heap->freeList[i].arena.next );
118
119 subheap = &heap->subheap;
120 while (subheap)
121 {
122 DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
123 DPRINT( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
124 (DWORD)subheap, subheap->size, subheap->commitSize );
125
126 DPRINT( "\n Block Stat Size Id\n" );
127 ptr = (char*)subheap + subheap->headerSize;
128 while (ptr < (char *)subheap + subheap->size)
129 {
130 if (*(DWORD *)ptr & ARENA_FLAG_FREE)
131 {
132 ARENA_FREE *pArena = (ARENA_FREE *)ptr;
133 DPRINT( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
134 (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
135 pArena->threadId, (DWORD)pArena->prev,
136 (DWORD)pArena->next);
137 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
138 arenaSize += sizeof(ARENA_FREE);
139 freeSize += pArena->size & ARENA_SIZE_MASK;
140 }
141 else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
142 {
143 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
144 DPRINT( "%08lx Used %08lx %04x back=%08lx EIP=%08lx\n",
145 (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
146 pArena->threadId, *((DWORD *)pArena - 1),
147 pArena->callerEIP );
148 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
149 arenaSize += sizeof(ARENA_INUSE);
150 usedSize += pArena->size & ARENA_SIZE_MASK;
151 }
152 else
153 {
154 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
155 DPRINT( "%08lx used %08lx %04x EIP=%08lx\n",
156 (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
157 pArena->threadId, pArena->callerEIP );
158 ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
159 arenaSize += sizeof(ARENA_INUSE);
160 usedSize += pArena->size & ARENA_SIZE_MASK;
161 }
162 }
163 DPRINT( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
164 subheap->size, subheap->commitSize, freeSize, usedSize,
165 arenaSize, (arenaSize * 100) / subheap->size );
166 subheap = subheap->next;
167 }
168 }
169
170
171 /***********************************************************************
172 * HEAP_GetPtr
173 * RETURNS
174 * Pointer to the heap
175 * NULL: Failure
176 */
177 static HEAP *HEAP_GetPtr(
178 HANDLE heap /* [in] Handle to the heap */
179 ) {
180 HEAP *heapPtr = (HEAP *)heap;
181 if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
182 {
183 DPRINT(heap, "Invalid heap %08x!\n", heap );
184 // SetLastError( ERROR_INVALID_HANDLE );
185 return NULL;
186 }
187 if (!RtlValidateHeap( heap, 0, NULL ))
188 {
189 HEAP_Dump( heapPtr );
190 DPRINT("NTDLL:%s:%d: assertion failed\n",__FILE__,__LINE__);
191 // SetLastError( ERROR_INVALID_HANDLE );
192 return NULL;
193 }
194 return heapPtr;
195 }
196
197
198 /***********************************************************************
199 * HEAP_InsertFreeBlock
200 *
201 * Insert a free block into the free list.
202 */
203 static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
204 {
205 FREE_LIST_ENTRY *pEntry = heap->freeList;
206 while (pEntry->size < pArena->size) pEntry++;
207 pArena->size |= ARENA_FLAG_FREE;
208 pArena->next = pEntry->arena.next;
209 pArena->next->prev = pArena;
210 pArena->prev = &pEntry->arena;
211 pEntry->arena.next = pArena;
212 }
213
214
215 /***********************************************************************
216 * HEAP_FindSubHeap
217 * Find the sub-heap containing a given address.
218 *
219 * RETURNS
220 * Pointer: Success
221 * NULL: Failure
222 */
223 static SUBHEAP *HEAP_FindSubHeap(
224 HEAP *heap, /* [in] Heap pointer */
225 LPCVOID ptr /* [in] Address */
226 ) {
227 SUBHEAP *sub = &heap->subheap;
228 while (sub)
229 {
230 if (((char *)ptr >= (char *)sub) &&
231 ((char *)ptr < (char *)sub + sub->size)) return sub;
232 sub = sub->next;
233 }
234 return NULL;
235 }
236
237
238 /***********************************************************************
239 * HEAP_Commit
240 *
241 * Make sure the heap storage is committed up to (not including) ptr.
242 */
243 static BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
244 {
245 DWORD size = (DWORD)((char *)ptr - (char *)subheap);
246 ULONG commitsize;
247 PVOID address;
248 NTSTATUS Status;
249
250 size = (size + 0xfff) & 0xfffff000; /* Align size on a page boundary */
251 if (size > subheap->size) size = subheap->size;
252 if (size <= subheap->commitSize) return TRUE;
253 commitsize = size - subheap->commitSize;
254 address = (PVOID)((char *)subheap + subheap->commitSize);
255 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
256 &address,
257 0,
258 &commitsize,
259 MEM_COMMIT,
260 PAGE_EXECUTE_READWRITE);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT("ZwAllocateVirtualMemory failed\n");
264 return(FALSE);
265 }
266 subheap->commitSize = size;
267 return TRUE;
268 }
269
270
271 /***********************************************************************
272 * HEAP_Decommit
273 *
274 * If possible, decommit the heap storage from (including) 'ptr'.
275 */
276 static BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
277 {
278 DWORD size = (DWORD)((char *)ptr - (char *)subheap);
279 PVOID freebase;
280 ULONG freesize;
281 NTSTATUS Status;
282
283 size = (size + 0xfff) & 0xfffff000; /* Align size on a page boundary */
284 if (size >= subheap->commitSize) return TRUE;
285 freebase = (PVOID)((char *)subheap + size);
286 freesize = subheap->commitSize - size;
287 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
288 &freebase,
289 &freesize,
290 MEM_DECOMMIT);
291 if (!NT_SUCCESS(Status))
292 {
293 DPRINT("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
294 subheap->commitSize - size,
295 (DWORD)((char *)subheap + size),
296 (DWORD)subheap->heap );
297 return FALSE;
298 }
299 subheap->commitSize = size;
300 return TRUE;
301 }
302
303
304 /***********************************************************************
305 * HEAP_CreateFreeBlock
306 *
307 * Create a free block at a specified address. 'size' is the size of the
308 * whole block, including the new arena.
309 */
310 static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
311 {
312 ARENA_FREE *pFree;
313
314 /* Create a free arena */
315
316 pFree = (ARENA_FREE *)ptr;
317 pFree->magic = ARENA_FREE_MAGIC;
318
319 /* If debugging, erase the freed block content */
320
321 if (1) // DEBUGGING
322 {
323 char *pEnd = (char *)ptr + size;
324 if (pEnd > (char *)subheap + subheap->commitSize)
325 pEnd = (char *)subheap + subheap->commitSize;
326 if (pEnd > (char *)(pFree + 1))
327 memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
328 }
329
330 /* Check if next block is free also */
331
332 if (((char *)ptr + size < (char *)subheap + subheap->size) &&
333 (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
334 {
335 /* Remove the next arena from the free list */
336 ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
337 pNext->next->prev = pNext->prev;
338 pNext->prev->next = pNext->next;
339 size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
340 if (1) // DEBUGGING
341 memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
342 }
343
344 /* Set the next block PREV_FREE flag and pointer */
345
346 if ((char *)ptr + size < (char *)subheap + subheap->size)
347 {
348 DWORD *pNext = (DWORD *)((char *)ptr + size);
349 *pNext |= ARENA_FLAG_PREV_FREE;
350 *(ARENA_FREE **)(pNext - 1) = pFree;
351 }
352
353 /* Last, insert the new block into the free list */
354
355 pFree->size = size - sizeof(*pFree);
356 HEAP_InsertFreeBlock( subheap->heap, pFree );
357 }
358
359
360 /***********************************************************************
361 * HEAP_MakeInUseBlockFree
362 *
363 * Turn an in-use block into a free block. Can also decommit the end of
364 * the heap, and possibly even free the sub-heap altogether.
365 */
366 static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
367 {
368 ARENA_FREE *pFree;
369 DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
370
371 /* Check if we can merge with previous block */
372
373 if (pArena->size & ARENA_FLAG_PREV_FREE)
374 {
375 pFree = *((ARENA_FREE **)pArena - 1);
376 size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
377 /* Remove it from the free list */
378 pFree->next->prev = pFree->prev;
379 pFree->prev->next = pFree->next;
380 }
381 else pFree = (ARENA_FREE *)pArena;
382
383 /* Create a free block */
384
385 HEAP_CreateFreeBlock( subheap, pFree, size );
386 size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
387 if ((char *)pFree + size < (char *)subheap + subheap->size)
388 return; /* Not the last block, so nothing more to do */
389
390 /* Free the whole sub-heap if it's empty and not the original one */
391
392 if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
393 (subheap != &subheap->heap->subheap))
394 {
395 SUBHEAP *pPrev = &subheap->heap->subheap;
396 /* Remove the free block from the list */
397 pFree->next->prev = pFree->prev;
398 pFree->prev->next = pFree->next;
399 /* Remove the subheap from the list */
400 while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
401 if (pPrev) pPrev->next = subheap->next;
402 /* Free the memory */
403 subheap->magic = 0;
404 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID*)&subheap, 0, MEM_RELEASE );
405 return;
406 }
407
408 /* Decommit the end of the heap */
409
410 HEAP_Decommit( subheap, pFree + 1 );
411 }
412
413
414 /***********************************************************************
415 * HEAP_ShrinkBlock
416 *
417 * Shrink an in-use block.
418 */
419 static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
420 {
421 if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
422 {
423 HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
424 (pArena->size & ARENA_SIZE_MASK) - size );
425 pArena->size = (pArena->size & ~ARENA_SIZE_MASK) | size;
426 }
427 else
428 {
429 /* Turn off PREV_FREE flag in next block */
430 char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
431 if (pNext < (char *)subheap + subheap->size)
432 *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
433 }
434 }
435
436 /***********************************************************************
437 * HEAP_InitSubHeap
438 */
439 static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
440 DWORD commitSize, DWORD totalSize )
441 {
442 SUBHEAP *subheap = (SUBHEAP *)address;
443 FREE_LIST_ENTRY *pEntry;
444 int i;
445 NTSTATUS Status;
446
447 /* Commit memory */
448
449 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
450 &address,
451 0,
452 (PULONG)&commitSize,
453 MEM_COMMIT,
454 PAGE_EXECUTE_READWRITE);
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT("Could not commit %08lx bytes for sub-heap %08lx\n",
458 commitSize, (DWORD)address );
459 return FALSE;
460 }
461
462
463 /* Fill the sub-heap structure */
464
465 subheap->heap = heap;
466 subheap->size = totalSize;
467 subheap->commitSize = commitSize;
468 subheap->magic = SUBHEAP_MAGIC;
469
470 if ( subheap != (SUBHEAP *)heap )
471 {
472 /* If this is a secondary subheap, insert it into list */
473
474 subheap->headerSize = sizeof(SUBHEAP);
475 subheap->next = heap->subheap.next;
476 heap->subheap.next = subheap;
477 }
478 else
479 {
480 /* If this is a primary subheap, initialize main heap */
481
482 subheap->headerSize = sizeof(HEAP);
483 subheap->next = NULL;
484 heap->next = NULL;
485 heap->flags = flags;
486 heap->magic = HEAP_MAGIC;
487
488 /* Build the free lists */
489
490 for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
491 {
492 pEntry->size = HEAP_freeListSizes[i];
493 pEntry->arena.size = 0 | ARENA_FLAG_FREE;
494 pEntry->arena.next = i < HEAP_NB_FREE_LISTS-1 ?
495 &heap->freeList[i+1].arena : &heap->freeList[0].arena;
496 pEntry->arena.prev = i ? &heap->freeList[i-1].arena :
497 &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
498 pEntry->arena.threadId = 0;
499 pEntry->arena.magic = ARENA_FREE_MAGIC;
500 }
501
502 /* Initialize critical section */
503
504 RtlInitializeCriticalSection( &heap->critSection );
505 }
506
507 /* Create the first free block */
508
509 HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize,
510 subheap->size - subheap->headerSize );
511
512 return TRUE;
513 }
514
515 /***********************************************************************
516 * HEAP_CreateSubHeap
517 *
518 * Create a sub-heap of the given size.
519 * If heap == NULL, creates a main heap.
520 */
521 static SUBHEAP *HEAP_CreateSubHeap(PVOID BaseAddress,
522 HEAP *heap,
523 DWORD flags,
524 DWORD commitSize,
525 DWORD totalSize )
526 {
527 LPVOID address;
528
529 /* Round-up sizes on a 64K boundary */
530
531 totalSize = (totalSize + 0xffff) & 0xffff0000;
532 commitSize = (commitSize + 0xffff) & 0xffff0000;
533 if (!commitSize) commitSize = 0x10000;
534 if (totalSize < commitSize) totalSize = commitSize;
535
536 /* Allocate the memory block */
537
538 address = BaseAddress;
539 ZwAllocateVirtualMemory(NtCurrentProcess(),
540 &address,
541 0,
542 (PULONG)&totalSize,
543 MEM_RESERVE,
544 PAGE_EXECUTE_READWRITE);
545
546 /* Initialize subheap */
547
548 if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address,
549 address, flags, commitSize, totalSize ))
550 {
551 ZwFreeVirtualMemory(NtCurrentProcess(), address, 0, MEM_RELEASE );
552 return NULL;
553 }
554
555 return (SUBHEAP *)address;
556 }
557
558
559 /***********************************************************************
560 * HEAP_FindFreeBlock
561 *
562 * Find a free block at least as large as the requested size, and make sure
563 * the requested size is committed.
564 */
565 static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
566 SUBHEAP **ppSubHeap )
567 {
568 SUBHEAP *subheap;
569 ARENA_FREE *pArena;
570 FREE_LIST_ENTRY *pEntry = heap->freeList;
571
572 /* Find a suitable free list, and in it find a block large enough */
573
574 while (pEntry->size < size) pEntry++;
575 pArena = pEntry->arena.next;
576 while (pArena != &heap->freeList[0].arena)
577 {
578 if (pArena->size > size)
579 {
580 subheap = HEAP_FindSubHeap( heap, pArena );
581 if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
582 + size + HEAP_MIN_BLOCK_SIZE))
583 return NULL;
584 *ppSubHeap = subheap;
585 return pArena;
586 }
587
588 pArena = pArena->next;
589 }
590
591 /* If no block was found, attempt to grow the heap */
592
593 if (!(heap->flags & HEAP_GROWABLE))
594 {
595 DPRINT("Not enough space in heap %08lx for %08lx bytes\n",
596 (DWORD)heap, size );
597 return NULL;
598 }
599 size += sizeof(SUBHEAP) + sizeof(ARENA_FREE);
600 if (!(subheap = HEAP_CreateSubHeap( NULL, heap, heap->flags, size,
601 max( HEAP_DEF_SIZE, size ) )))
602 return NULL;
603
604 DPRINT("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
605 (DWORD)subheap, size, (DWORD)heap );
606
607 *ppSubHeap = subheap;
608 return (ARENA_FREE *)(subheap + 1);
609 }
610
611
612 /***********************************************************************
613 * HEAP_IsValidArenaPtr
614 *
615 * Check that the pointer is inside the range possible for arenas.
616 */
617 static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
618 {
619 int i;
620 SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
621 if (!subheap) return FALSE;
622 if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
623 if (subheap != &heap->subheap) return FALSE;
624 for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
625 if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
626 return FALSE;
627 }
628
629
630 /***********************************************************************
631 * HEAP_ValidateFreeArena
632 */
633 static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
634 {
635 char *heapEnd = (char *)subheap + subheap->size;
636
637 /* Check magic number */
638 if (pArena->magic != ARENA_FREE_MAGIC)
639 {
640 DPRINT("Heap %08lx: invalid free arena magic for %08lx\n",
641 (DWORD)subheap->heap, (DWORD)pArena );
642 return FALSE;
643 }
644 /* Check size flags */
645 if (!(pArena->size & ARENA_FLAG_FREE) ||
646 (pArena->size & ARENA_FLAG_PREV_FREE))
647 {
648 DPRINT("Heap %08lx: bad flags %lx for free arena %08lx\n",
649 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
650 }
651 /* Check arena size */
652 if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
653 {
654 DPRINT("Heap %08lx: bad size %08lx for free arena %08lx\n",
655 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
656 return FALSE;
657 }
658 /* Check that next pointer is valid */
659 if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
660 {
661 DPRINT("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
662 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
663 return FALSE;
664 }
665 /* Check that next arena is free */
666 if (!(pArena->next->size & ARENA_FLAG_FREE) ||
667 (pArena->next->magic != ARENA_FREE_MAGIC))
668 {
669 DPRINT("Heap %08lx: next arena %08lx invalid for %08lx\n",
670 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
671 return FALSE;
672 }
673 /* Check that prev pointer is valid */
674 if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
675 {
676 DPRINT("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
677 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
678 return FALSE;
679 }
680 /* Check that prev arena is free */
681 if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
682 (pArena->prev->magic != ARENA_FREE_MAGIC))
683 {
684 DPRINT("Heap %08lx: prev arena %08lx invalid for %08lx\n",
685 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
686 return FALSE;
687 }
688 /* Check that next block has PREV_FREE flag */
689 if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
690 {
691 if (!(*(DWORD *)((char *)(pArena + 1) +
692 (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
693 {
694 DPRINT("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
695 (DWORD)subheap->heap, (DWORD)pArena );
696 return FALSE;
697 }
698 /* Check next block back pointer */
699 if (*((ARENA_FREE **)((char *)(pArena + 1) +
700 (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
701 {
702 DPRINT("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
703 (DWORD)subheap->heap, (DWORD)pArena,
704 *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
705 return FALSE;
706 }
707 }
708 return TRUE;
709 }
710
711
712 /***********************************************************************
713 * HEAP_ValidateInUseArena
714 */
715 static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena )
716 {
717 char *heapEnd = (char *)subheap + subheap->size;
718
719 /* Check magic number */
720 if (pArena->magic != ARENA_INUSE_MAGIC)
721 {
722 DPRINT("Heap %08lx: invalid in-use arena magic for %08lx\n",
723 (DWORD)subheap->heap, (DWORD)pArena );
724 return FALSE;
725 }
726 /* Check size flags */
727 if (pArena->size & ARENA_FLAG_FREE)
728 {
729 DPRINT("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
730 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
731 }
732 /* Check arena size */
733 if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
734 {
735 DPRINT("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
736 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
737 return FALSE;
738 }
739 /* Check next arena PREV_FREE flag */
740 if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
741 (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
742 {
743 DPRINT("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
744 (DWORD)subheap->heap, (DWORD)pArena );
745 return FALSE;
746 }
747 /* Check prev free arena */
748 if (pArena->size & ARENA_FLAG_PREV_FREE)
749 {
750 ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
751 /* Check prev pointer */
752 if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
753 {
754 DPRINT("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
755 (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
756 return FALSE;
757 }
758 /* Check that prev arena is free */
759 if (!(pPrev->size & ARENA_FLAG_FREE) ||
760 (pPrev->magic != ARENA_FREE_MAGIC))
761 {
762 DPRINT("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n",
763 (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
764 return FALSE;
765 }
766 /* Check that prev arena is really the previous block */
767 if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
768 {
769 DPRINT("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
770 (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
771 return FALSE;
772 }
773 }
774 return TRUE;
775 }
776
777
778 /***********************************************************************
779 * HEAP_IsInsideHeap
780 * Checks whether the pointer points to a block inside a given heap.
781 *
782 * NOTES
783 * Should this return BOOL32?
784 *
785 * RETURNS
786 * !0: Success
787 * 0: Failure
788 */
789 int HEAP_IsInsideHeap(
790 HANDLE heap, /* [in] Heap */
791 DWORD flags, /* [in] Flags */
792 LPCVOID ptr /* [in] Pointer */
793 ) {
794 HEAP *heapPtr = HEAP_GetPtr( heap );
795 SUBHEAP *subheap;
796 int ret;
797
798 /* Validate the parameters */
799
800 if (!heapPtr) return 0;
801 flags |= heapPtr->flags;
802 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
803 ret = (((subheap = HEAP_FindSubHeap( heapPtr, ptr )) != NULL) &&
804 (((char *)ptr >= (char *)subheap + subheap->headerSize
805 + sizeof(ARENA_INUSE))));
806 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
807 return ret;
808 }
809
810
811 /***********************************************************************
812 * HeapCreate (KERNEL32.336)
813 * RETURNS
814 * Handle of heap: Success
815 * NULL: Failure
816 */
817 HANDLE STDCALL RtlCreateHeap(ULONG flags,
818 PVOID BaseAddress,
819 ULONG initialSize,
820 ULONG maxSize,
821 PVOID Unknown,
822 PRTL_HEAP_DEFINITION Definition)
823 {
824 SUBHEAP *subheap;
825
826 /* Allocate the heap block */
827
828 DPRINT("RtlCreateHeap(flags %x, BaseAddress %x, initialSize %x, "
829 "maxSize %x\n)",flags,BaseAddress,initialSize, maxSize);
830
831 if (!maxSize)
832 {
833 maxSize = HEAP_DEF_SIZE;
834 flags |= HEAP_GROWABLE;
835 }
836 if (!(subheap = HEAP_CreateSubHeap(BaseAddress,
837 NULL,
838 flags,
839 initialSize,
840 maxSize)))
841 {
842 // SetLastError( ERROR_OUTOFMEMORY );
843 DPRINT("RtlCreateHeap() = %x\n",0);
844 return 0;
845 }
846
847 DPRINT("RtlCreateHeap() = %x\n",subheap);
848
849 return (HANDLE)subheap;
850 }
851
852 /***********************************************************************
853 * HeapDestroy (KERNEL32.337)
854 * RETURNS
855 * TRUE: Success
856 * FALSE: Failure
857 */
858 BOOL WINAPI RtlDestroyHeap(
859 HANDLE heap /* [in] Handle of heap */
860 ) {
861 HEAP *heapPtr = HEAP_GetPtr( heap );
862 SUBHEAP *subheap;
863
864 DPRINT("%08x\n", heap );
865 if (!heapPtr) return FALSE;
866
867 RtlDeleteCriticalSection( &heapPtr->critSection );
868 subheap = &heapPtr->subheap;
869 while (subheap)
870 {
871 SUBHEAP *next = subheap->next;
872 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID*)&subheap, 0, MEM_RELEASE );
873 subheap = next;
874 }
875 return TRUE;
876 }
877
878
879 /***********************************************************************
880 * HeapAlloc (KERNEL32.334)
881 * RETURNS
882 * Pointer to allocated memory block
883 * NULL: Failure
884 */
885 PVOID WINAPI RtlAllocateHeap(
886 HANDLE heap, /* [in] Handle of private heap block */
887 ULONG flags, /* [in] Heap allocation control flags */
888 ULONG size /* [in] Number of bytes to allocate */
889 ) {
890 ARENA_FREE *pArena;
891 ARENA_INUSE *pInUse;
892 SUBHEAP *subheap;
893 HEAP *heapPtr = HEAP_GetPtr( heap );
894
895 /* Validate the parameters */
896
897 if (!heapPtr) return NULL;
898 flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
899 flags |= heapPtr->flags;
900 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
901 size = (size + 3) & ~3;
902 if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
903
904 /* Locate a suitable free block */
905
906 if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
907 {
908 DPRINT("(%08x,%08lx,%08lx): returning NULL\n",
909 heap, flags, size );
910 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
911 // SetLastError( ERROR_COMMITMENT_LIMIT );
912 return NULL;
913 }
914
915 /* Remove the arena from the free list */
916
917 pArena->next->prev = pArena->prev;
918 pArena->prev->next = pArena->next;
919
920 /* Build the in-use arena */
921
922 pInUse = (ARENA_INUSE *)pArena;
923 pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
924 + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
925 pInUse->callerEIP = *((DWORD *)&heap - 1); /* hack hack */
926 // pInUse->threadId = GetCurrentTask();
927 pInUse->magic = ARENA_INUSE_MAGIC;
928
929 /* Shrink the block */
930
931 HEAP_ShrinkBlock( subheap, pInUse, size );
932
933 if (flags & HEAP_ZERO_MEMORY) memset( pInUse + 1, 0, size );
934 else if (1) memset( pInUse + 1, ARENA_INUSE_FILLER, size ); //DEBUGGING
935
936 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
937
938 DPRINT("(%08x,%08lx,%08lx): returning %08lx\n",
939 heap, flags, size, (DWORD)(pInUse + 1) );
940 return (LPVOID)(pInUse + 1);
941 }
942
943
944 /***********************************************************************
945 * HeapFree (KERNEL32.338)
946 * RETURNS
947 * TRUE: Success
948 * FALSE: Failure
949 */
950 BOOLEAN STDCALL RtlFreeHeap(
951 HANDLE heap, /* [in] Handle of heap */
952 ULONG flags, /* [in] Heap freeing flags */
953 PVOID ptr /* [in] Address of memory to free */
954 ) {
955 ARENA_INUSE *pInUse;
956 SUBHEAP *subheap;
957 HEAP *heapPtr = HEAP_GetPtr( heap );
958
959 /* Validate the parameters */
960
961 if (!heapPtr) return FALSE;
962 flags &= HEAP_NO_SERIALIZE;
963 flags |= heapPtr->flags;
964 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
965 if (!ptr)
966 {
967 DPRINT("(%08x,%08lx,%08lx): asked to free NULL\n",
968 heap, flags, (DWORD)ptr );
969 }
970 if (!ptr || !RtlValidateHeap( heap, HEAP_NO_SERIALIZE, ptr ))
971 {
972 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
973 // SetLastError( ERROR_INVALID_PARAMETER );
974 DPRINT("(%08x,%08lx,%08lx): returning FALSE\n",
975 heap, flags, (DWORD)ptr );
976 return FALSE;
977 }
978
979 /* Turn the block into a free block */
980
981 pInUse = (ARENA_INUSE *)ptr - 1;
982 subheap = HEAP_FindSubHeap( heapPtr, pInUse );
983 HEAP_MakeInUseBlockFree( subheap, pInUse );
984
985 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
986 /* SetLastError( 0 ); */
987
988 DPRINT("(%08x,%08lx,%08lx): returning TRUE\n",
989 heap, flags, (DWORD)ptr );
990 return TRUE;
991 }
992
993
994 /***********************************************************************
995 * HeapReAlloc (KERNEL32.340)
996 * RETURNS
997 * Pointer to reallocated memory block
998 * NULL: Failure
999 *
1000 * REVISIONS
1001 * Renamed RtlReAllocateHeap as in NT
1002 */
1003 LPVOID
1004 WINAPI
1005 RtlReAllocateHeap (
1006 HANDLE heap, /* [in] Handle of heap block */
1007 DWORD flags, /* [in] Heap reallocation flags */
1008 LPVOID ptr, /* [in] Address of memory to reallocate */
1009 DWORD size /* [in] Number of bytes to reallocate */
1010 )
1011 {
1012 ARENA_INUSE *pArena;
1013 DWORD oldSize;
1014 HEAP *heapPtr;
1015 SUBHEAP *subheap;
1016
1017 if (!ptr) return RtlAllocateHeap( heap, flags, size ); /* FIXME: correct? */
1018 if (!(heapPtr = HEAP_GetPtr( heap ))) return FALSE;
1019
1020 /* Validate the parameters */
1021
1022 flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
1023 HEAP_REALLOC_IN_PLACE_ONLY;
1024 flags |= heapPtr->flags;
1025 size = (size + 3) & ~3;
1026 if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
1027
1028 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
1029 if (!RtlValidateHeap( heap, HEAP_NO_SERIALIZE, ptr ))
1030 {
1031 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1032 // SetLastError( ERROR_INVALID_PARAMETER );
1033 DPRINT("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
1034 heap, flags, (DWORD)ptr, size );
1035 return NULL;
1036 }
1037
1038 /* Check if we need to grow the block */
1039
1040 pArena = (ARENA_INUSE *)ptr - 1;
1041 // pArena->threadId = GetCurrentTask();
1042 subheap = HEAP_FindSubHeap( heapPtr, pArena );
1043 oldSize = (pArena->size & ARENA_SIZE_MASK);
1044 if (size > oldSize)
1045 {
1046 char *pNext = (char *)(pArena + 1) + oldSize;
1047 if ((pNext < (char *)subheap + subheap->size) &&
1048 (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
1049 (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
1050 {
1051 /* The next block is free and large enough */
1052 ARENA_FREE *pFree = (ARENA_FREE *)pNext;
1053 pFree->next->prev = pFree->prev;
1054 pFree->prev->next = pFree->next;
1055 pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
1056 if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
1057 + size + HEAP_MIN_BLOCK_SIZE))
1058 {
1059 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1060 // SetLastError( ERROR_OUTOFMEMORY );
1061 return NULL;
1062 }
1063 HEAP_ShrinkBlock( subheap, pArena, size );
1064 }
1065 else /* Do it the hard way */
1066 {
1067 ARENA_FREE *pNew;
1068 ARENA_INUSE *pInUse;
1069 SUBHEAP *newsubheap;
1070
1071 if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
1072 !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
1073 {
1074 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1075 // SetLastError( ERROR_OUTOFMEMORY );
1076 return NULL;
1077 }
1078
1079 /* Build the in-use arena */
1080
1081 pNew->next->prev = pNew->prev;
1082 pNew->prev->next = pNew->next;
1083 pInUse = (ARENA_INUSE *)pNew;
1084 pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
1085 + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
1086 // pInUse->threadId = GetCurrentTask();
1087 pInUse->magic = ARENA_INUSE_MAGIC;
1088 HEAP_ShrinkBlock( newsubheap, pInUse, size );
1089 memcpy( pInUse + 1, pArena + 1, oldSize );
1090
1091 /* Free the previous block */
1092
1093 HEAP_MakeInUseBlockFree( subheap, pArena );
1094 subheap = newsubheap;
1095 pArena = pInUse;
1096 }
1097 }
1098 else HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */
1099
1100 /* Clear the extra bytes if needed */
1101
1102 if (size > oldSize)
1103 {
1104 if (flags & HEAP_ZERO_MEMORY)
1105 memset( (char *)(pArena + 1) + oldSize, 0,
1106 (pArena->size & ARENA_SIZE_MASK) - oldSize );
1107 else if (1) // DEBUGGING
1108 memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
1109 (pArena->size & ARENA_SIZE_MASK) - oldSize );
1110 }
1111
1112 /* Return the new arena */
1113
1114 pArena->callerEIP = *((DWORD *)&heap - 1); /* hack hack */
1115 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1116
1117 DPRINT("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
1118 heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
1119 return (LPVOID)(pArena + 1);
1120 }
1121
1122
1123 /***********************************************************************
1124 * HeapCompact (KERNEL32.335)
1125 */
1126 DWORD WINAPI RtlCompactHeap( HANDLE heap, DWORD flags )
1127 {
1128 return 0;
1129 }
1130
1131
1132 /***********************************************************************
1133 * HeapLock (KERNEL32.339)
1134 * Attempts to acquire the critical section object for a specified heap.
1135 *
1136 * RETURNS
1137 * TRUE: Success
1138 * FALSE: Failure
1139 */
1140 BOOL WINAPI RtlLockHeap(
1141 HANDLE heap /* [in] Handle of heap to lock for exclusive access */
1142 ) {
1143 HEAP *heapPtr = HEAP_GetPtr( heap );
1144 if (!heapPtr) return FALSE;
1145 RtlEnterCriticalSection( &heapPtr->critSection );
1146 return TRUE;
1147 }
1148
1149
1150 /***********************************************************************
1151 * HeapUnlock (KERNEL32.342)
1152 * Releases ownership of the critical section object.
1153 *
1154 * RETURNS
1155 * TRUE: Success
1156 * FALSE: Failure
1157 */
1158 BOOL WINAPI RtlUnlockHeap(
1159 HANDLE heap /* [in] Handle to the heap to unlock */
1160 ) {
1161 HEAP *heapPtr = HEAP_GetPtr( heap );
1162 if (!heapPtr) return FALSE;
1163 RtlLeaveCriticalSection( &heapPtr->critSection );
1164 return TRUE;
1165 }
1166
1167
1168 /***********************************************************************
1169 * HeapSize (KERNEL32.341)
1170 * RETURNS
1171 * Size in bytes of allocated memory
1172 * 0: Failure
1173 */
1174 DWORD WINAPI RtlSizeHeap(
1175 HANDLE heap, /* [in] Handle of heap */
1176 DWORD flags, /* [in] Heap size control flags */
1177 LPVOID ptr /* [in] Address of memory to return size for */
1178 ) {
1179 DWORD ret;
1180 HEAP *heapPtr = HEAP_GetPtr( heap );
1181
1182 if (!heapPtr) return FALSE;
1183 flags &= HEAP_NO_SERIALIZE;
1184 flags |= heapPtr->flags;
1185 if (!(flags & HEAP_NO_SERIALIZE)) RtlLockHeap( heap );
1186 if (!RtlValidateHeap( heap, HEAP_NO_SERIALIZE, ptr ))
1187 {
1188 // SetLastError( ERROR_INVALID_PARAMETER );
1189 ret = 0xffffffff;
1190 }
1191 else
1192 {
1193 ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
1194 ret = pArena->size & ARENA_SIZE_MASK;
1195 }
1196 if (!(flags & HEAP_NO_SERIALIZE)) RtlUnlockHeap( heap );
1197
1198 DPRINT("(%08x,%08lx,%08lx): returning %08lx\n",
1199 heap, flags, (DWORD)ptr, ret );
1200 return ret;
1201 }
1202
1203
1204 /***********************************************************************
1205 * HeapValidate (KERNEL32.343)
1206 * Validates a specified heap.
1207 *
1208 * NOTES
1209 * Flags is ignored.
1210 *
1211 * RETURNS
1212 * TRUE: Success
1213 * FALSE: Failure
1214 */
1215 BOOL WINAPI RtlValidateHeap(
1216 HANDLE heap, /* [in] Handle to the heap */
1217 DWORD flags, /* [in] Bit flags that control access during operation */
1218 PVOID block /* [in] Optional pointer to memory block to validate */
1219 ) {
1220 SUBHEAP *subheap;
1221 HEAP *heapPtr = (HEAP *)(heap);
1222
1223 if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
1224 {
1225 DPRINT("Invalid heap %08x!\n", heap );
1226 return FALSE;
1227 }
1228
1229 if (block)
1230 {
1231 /* Only check this single memory block */
1232 if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
1233 ((char *)block < (char *)subheap + subheap->headerSize
1234 + sizeof(ARENA_INUSE)))
1235 {
1236 DPRINT("Heap %08lx: block %08lx is not inside heap\n",
1237 (DWORD)heap, (DWORD)block );
1238 return FALSE;
1239 }
1240 return HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1 );
1241 }
1242
1243 subheap = &heapPtr->subheap;
1244 while (subheap)
1245 {
1246 char *ptr = (char *)subheap + subheap->headerSize;
1247 while (ptr < (char *)subheap + subheap->size)
1248 {
1249 if (*(DWORD *)ptr & ARENA_FLAG_FREE)
1250 {
1251 if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr ))
1252 return FALSE;
1253 ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
1254 }
1255 else
1256 {
1257 if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr ))
1258 return FALSE;
1259 ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
1260 }
1261 }
1262 subheap = subheap->next;
1263 }
1264 return TRUE;
1265 }
1266
1267 HANDLE WINAPI RtlGetProcessHeap(VOID)
1268 {
1269 DPRINT("RtlGetProcessHeap()\n");
1270 return (HANDLE)NtCurrentPeb()->ProcessHeap;
1271 }
1272