1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/image.c
4 * PURPOSE: Image handling functions
5 * PROGRAMMERS: Copyright 1996 Alexandre Julliard
6 * Copyright 1998 Ulrich Weigand
9 /* Note: the heap data structures are based on what Pietrek describes in his
10 * book 'Windows 95 System Programming Secrets'. The layout is not exactly
11 * the same, but could be easily adapted if it turns out some programs
15 /* INCLUDES *****************************************************************/
22 /* FUNCTIONS *****************************************************************/
24 #define WARN_ON(x) (1)
27 #define TRACE_ON(x) (0)
29 #define TRACE_ON(x) (1)
32 static RTL_CRITICAL_SECTION RtlpProcessHeapsListLock
;
35 typedef struct tagARENA_INUSE
37 ULONG size
; /* Block size; must be the first field */
38 USHORT threadId
; /* Allocating thread id */
39 USHORT magic
; /* Magic number */
43 typedef struct tagARENA_FREE
45 ULONG size
; /* Block size; must be the first field */
46 USHORT threadId
; /* Freeing thread id */
47 USHORT magic
; /* Magic number */
48 struct tagARENA_FREE
*next
; /* Next free arena */
49 struct tagARENA_FREE
*prev
; /* Prev free arena */
53 #define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */
54 #define ARENA_FLAG_PREV_FREE 0x00000002
55 #define ARENA_SIZE_MASK 0xfffffffc
56 #define ARENA_INUSE_MAGIC 0x4842 /* Value for arena 'magic' field */
57 #define ARENA_FREE_MAGIC 0x4846 /* Value for arena 'magic' field */
59 #define ARENA_INUSE_FILLER 0x55
60 #define ARENA_FREE_FILLER 0xaa
62 #define QUIET 1 /* Suppress messages */
63 #define NOISY 0 /* Report all errors */
65 #define HEAP_NB_FREE_LISTS 4 /* Number of free lists */
67 /* Max size of the blocks on the free lists */
68 static const ULONG HEAP_freeListSizes
[HEAP_NB_FREE_LISTS
] =
70 0x20, 0x80, 0x200, 0xffffffff
82 typedef struct tagSUBHEAP
84 ULONG size
; /* Size of the whole sub-heap */
85 ULONG commitSize
; /* Committed size of the sub-heap */
86 ULONG headerSize
; /* Size of the heap header */
87 struct tagSUBHEAP
*next
; /* Next sub-heap */
88 struct tagHEAP
*heap
; /* Main heap structure */
89 ULONG magic
; /* Magic number */
93 #define SUBHEAP_MAGIC ((ULONG)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
95 typedef struct tagHEAP
97 SUBHEAP subheap
; /* First sub-heap */
98 struct tagHEAP
*next
; /* Next heap for this process */
99 FREE_LIST_ENTRY freeList
[HEAP_NB_FREE_LISTS
]; /* Free lists */
100 RTL_CRITICAL_SECTION critSection
; /* Critical section for serialization */
101 ULONG flags
; /* Heap flags */
102 ULONG magic
; /* Magic number */
103 PRTL_HEAP_COMMIT_ROUTINE commitRoutine
;
107 #define HEAP_MAGIC ((ULONG)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
109 #define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
110 #define HEAP_MIN_BLOCK_SIZE (sizeof(ARENA_FREE) + 8) /* Min. heap block size */
111 #define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */
114 static BOOLEAN
HEAP_IsRealArena( HANDLE heap
, ULONG flags
, PVOID block
, BOOLEAN quiet
);
117 /***********************************************************************
121 HEAP_Dump(PHEAP heap
)
127 DPRINT( "Heap: %p\n", heap
);
128 DPRINT( "Next: %p Sub-heaps: %p",
129 heap
->next
, &heap
->subheap
);
130 subheap
= &heap
->subheap
;
131 while (subheap
->next
)
133 DPRINT( " -> %p", subheap
->next
);
134 subheap
= subheap
->next
;
137 DPRINT( "\nFree lists:\n Block Stat Size Id\n" );
138 for (i
= 0; i
< HEAP_NB_FREE_LISTS
; i
++)
139 DPRINT( "%p free %08lx %04x prev=%p next=%p\n",
140 &heap
->freeList
[i
].arena
,
141 heap
->freeList
[i
].arena
.size
,
142 heap
->freeList
[i
].arena
.threadId
,
143 heap
->freeList
[i
].arena
.prev
,
144 heap
->freeList
[i
].arena
.next
);
146 subheap
= &heap
->subheap
;
149 ULONG freeSize
= 0, usedSize
= 0, arenaSize
= subheap
->headerSize
;
150 DPRINT( "\n\nSub-heap %p: size=%08lx committed=%08lx\n",
151 subheap
, subheap
->size
, subheap
->commitSize
);
153 DPRINT( "\n Block Stat Size Id\n" );
154 ptr
= (char*)subheap
+ subheap
->headerSize
;
155 while (ptr
< (char *)subheap
+ subheap
->size
)
157 if (*(PULONG
)ptr
& ARENA_FLAG_FREE
)
159 ARENA_FREE
*pArena
= (ARENA_FREE
*)ptr
;
160 DPRINT( "%p free %08lx %04x prev=%p next=%p\n",
161 pArena
, pArena
->size
& ARENA_SIZE_MASK
,
162 pArena
->threadId
, pArena
->prev
,
164 ptr
+= sizeof(*pArena
) + (pArena
->size
& ARENA_SIZE_MASK
);
165 arenaSize
+= sizeof(ARENA_FREE
);
166 freeSize
+= pArena
->size
& ARENA_SIZE_MASK
;
168 else if (*(PULONG
)ptr
& ARENA_FLAG_PREV_FREE
)
170 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)ptr
;
171 DPRINT( "%p Used %08lx %04x back=%08lx\n",
172 pArena
, pArena
->size
& ARENA_SIZE_MASK
,
173 pArena
->threadId
, *((PULONG
)pArena
- 1));
174 ptr
+= sizeof(*pArena
) + (pArena
->size
& ARENA_SIZE_MASK
);
175 arenaSize
+= sizeof(ARENA_INUSE
);
176 usedSize
+= pArena
->size
& ARENA_SIZE_MASK
;
180 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)ptr
;
181 DPRINT( "%p used %08lx %04x\n",
182 pArena
, pArena
->size
& ARENA_SIZE_MASK
,
184 ptr
+= sizeof(*pArena
) + (pArena
->size
& ARENA_SIZE_MASK
);
185 arenaSize
+= sizeof(ARENA_INUSE
);
186 usedSize
+= pArena
->size
& ARENA_SIZE_MASK
;
189 DPRINT( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
190 subheap
->size
, subheap
->commitSize
, freeSize
, usedSize
,
191 arenaSize
, (arenaSize
* 100) / subheap
->size
);
192 subheap
= subheap
->next
;
197 /***********************************************************************
200 * Pointer to the heap
204 HEAP_GetPtr(HANDLE heap
) /* [in] Handle to the heap */
206 HEAP
*heapPtr
= (HEAP
*)heap
;
207 if (!heapPtr
|| (heapPtr
->magic
!= HEAP_MAGIC
))
209 DPRINT("Invalid heap %08x!\n", heap
);
212 if (TRACE_ON(heap
) && !HEAP_IsRealArena( heap
, 0, NULL
, NOISY
))
214 HEAP_Dump( heapPtr
);
222 /***********************************************************************
223 * HEAP_InsertFreeBlock
225 * Insert a free block into the free list.
228 HEAP_InsertFreeBlock(PHEAP heap
,
232 FREE_LIST_ENTRY
*pEntry
= heap
->freeList
;
233 while (pEntry
->size
< pArena
->size
)
237 /* insert at end of free list, i.e. before next free list entry */
239 if (pEntry
== &heap
->freeList
[HEAP_NB_FREE_LISTS
])
241 pEntry
= heap
->freeList
;
243 pArena
->prev
= pEntry
->arena
.prev
;
244 pArena
->prev
->next
= pArena
;
245 pArena
->next
= &pEntry
->arena
;
246 pEntry
->arena
.prev
= pArena
;
250 /* insert at head of free list */
251 pArena
->next
= pEntry
->arena
.next
;
252 pArena
->next
->prev
= pArena
;
253 pArena
->prev
= &pEntry
->arena
;
254 pEntry
->arena
.next
= pArena
;
256 pArena
->size
|= ARENA_FLAG_FREE
;
260 /***********************************************************************
262 * Find the sub-heap containing a given address.
269 HEAP_FindSubHeap(HEAP
*heap
, /* [in] Heap pointer */
270 PVOID ptr
) /* [in] Address */
272 PSUBHEAP sub
= &heap
->subheap
;
275 if (((char *)ptr
>= (char *)sub
) &&
276 ((char *)ptr
< (char *)sub
+ sub
->size
))
284 /***********************************************************************
287 * Make sure the heap storage is committed up to (not including) ptr.
289 static __inline BOOLEAN
290 HEAP_Commit(SUBHEAP
*subheap
,
294 ULONG size
= (ULONG
)((char *)ptr
- (char *)subheap
);
299 size
= (size
+ COMMIT_MASK
) & ~COMMIT_MASK
;
300 if (size
> subheap
->size
)
301 size
= subheap
->size
;
302 if (size
<= subheap
->commitSize
)
305 address
= (PVOID
)((char *)subheap
+ subheap
->commitSize
);
306 commitsize
= size
- subheap
->commitSize
;
308 if (subheap
->heap
->commitRoutine
!= NULL
)
310 Status
= subheap
->heap
->commitRoutine(subheap
->heap
, &address
, &commitsize
);
314 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
319 PAGE_EXECUTE_READWRITE
);
321 if (!NT_SUCCESS(Status
))
323 DPRINT( "Could not commit %08lx bytes at %p for heap %p\n",
324 size
- subheap
->commitSize
,
325 ((char *)subheap
+ subheap
->commitSize
),
330 subheap
->commitSize
+= commitsize
;
336 /***********************************************************************
339 * If possible, decommit the heap storage from (including) 'ptr'.
341 static inline BOOLEAN
HEAP_Decommit( SUBHEAP
*subheap
, PVOID ptr
, ULONG flags
)
343 ULONG size
= (ULONG
)((char *)ptr
- (char *)subheap
);
347 /* round to next block and add one full block */
348 size
= ((size
+ COMMIT_MASK
) & ~COMMIT_MASK
) + COMMIT_MASK
+ 1;
349 if (size
>= subheap
->commitSize
)
352 address
= (PVOID
)((char *)subheap
+ size
);
353 decommitsize
= subheap
->commitSize
- size
;
355 Status
= ZwFreeVirtualMemory(NtCurrentProcess(),
359 if (!NT_SUCCESS(Status
))
361 DPRINT( "Could not decommit %08lx bytes at %p for heap %p\n",
362 subheap
->commitSize
- size
,
363 ((char *)subheap
+ size
),
368 subheap
->commitSize
-= decommitsize
;
373 /***********************************************************************
374 * HEAP_CreateFreeBlock
376 * Create a free block at a specified address. 'size' is the size of the
377 * whole block, including the new arena.
379 static VOID
HEAP_CreateFreeBlock( SUBHEAP
*subheap
, PVOID ptr
, ULONG size
)
384 /* Create a free arena */
386 pFree
= (ARENA_FREE
*)ptr
;
387 pFree
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
388 pFree
->magic
= ARENA_FREE_MAGIC
;
390 /* If debugging, erase the freed block content */
394 char *pEnd
= (char *)ptr
+ size
;
395 if (pEnd
> (char *)subheap
+ subheap
->commitSize
)
396 pEnd
= (char *)subheap
+ subheap
->commitSize
;
397 if (pEnd
> (char *)(pFree
+ 1))
398 memset( pFree
+ 1, ARENA_FREE_FILLER
, pEnd
- (char *)(pFree
+ 1) );
401 /* Check if next block is free also */
403 if (((char *)ptr
+ size
< (char *)subheap
+ subheap
->size
) &&
404 (*(PULONG
)((char *)ptr
+ size
) & ARENA_FLAG_FREE
))
406 /* Remove the next arena from the free list */
407 ARENA_FREE
*pNext
= (ARENA_FREE
*)((char *)ptr
+ size
);
408 pNext
->next
->prev
= pNext
->prev
;
409 pNext
->prev
->next
= pNext
->next
;
410 size
+= (pNext
->size
& ARENA_SIZE_MASK
) + sizeof(*pNext
);
412 memset( pNext
, ARENA_FREE_FILLER
, sizeof(ARENA_FREE
) );
415 /* Set the next block PREV_FREE flag and pointer */
417 last
= ((char *)ptr
+ size
>= (char *)subheap
+ subheap
->size
);
420 PULONG pNext
= (PULONG
)((char *)ptr
+ size
);
421 *pNext
|= ARENA_FLAG_PREV_FREE
;
422 *(ARENA_FREE
**)(pNext
- 1) = pFree
;
425 /* Last, insert the new block into the free list */
427 pFree
->size
= size
- sizeof(*pFree
);
428 HEAP_InsertFreeBlock( subheap
->heap
, pFree
, last
);
432 /***********************************************************************
433 * HEAP_MakeInUseBlockFree
435 * Turn an in-use block into a free block. Can also decommit the end of
436 * the heap, and possibly even free the sub-heap altogether.
438 static VOID
HEAP_MakeInUseBlockFree( SUBHEAP
*subheap
, ARENA_INUSE
*pArena
,
442 ULONG size
= (pArena
->size
& ARENA_SIZE_MASK
) + sizeof(*pArena
);
445 /* Check if we can merge with previous block */
447 if (pArena
->size
& ARENA_FLAG_PREV_FREE
)
449 pFree
= *((ARENA_FREE
**)pArena
- 1);
450 size
+= (pFree
->size
& ARENA_SIZE_MASK
) + sizeof(ARENA_FREE
);
451 /* Remove it from the free list */
452 pFree
->next
->prev
= pFree
->prev
;
453 pFree
->prev
->next
= pFree
->next
;
456 pFree
= (ARENA_FREE
*)pArena
;
458 /* Create a free block */
460 HEAP_CreateFreeBlock( subheap
, pFree
, size
);
461 size
= (pFree
->size
& ARENA_SIZE_MASK
) + sizeof(ARENA_FREE
);
462 if ((char *)pFree
+ size
< (char *)subheap
+ subheap
->size
)
463 return; /* Not the last block, so nothing more to do */
465 /* Free the whole sub-heap if it's empty and not the original one */
467 if (((char *)pFree
== (char *)subheap
+ subheap
->headerSize
) &&
468 (subheap
!= &subheap
->heap
->subheap
))
470 SUBHEAP
*pPrev
= &subheap
->heap
->subheap
;
471 /* Remove the free block from the list */
472 pFree
->next
->prev
= pFree
->prev
;
473 pFree
->prev
->next
= pFree
->next
;
474 /* Remove the subheap from the list */
475 while (pPrev
&& (pPrev
->next
!= subheap
))
478 pPrev
->next
= subheap
->next
;
479 /* Free the memory */
481 ZwFreeVirtualMemory(NtCurrentProcess(),
488 /* Decommit the end of the heap */
492 /***********************************************************************
495 * Shrink an in-use block.
497 static void HEAP_ShrinkBlock(SUBHEAP
*subheap
, ARENA_INUSE
*pArena
, ULONG size
)
499 if ((pArena
->size
& ARENA_SIZE_MASK
) >= size
+ HEAP_MIN_BLOCK_SIZE
)
501 HEAP_CreateFreeBlock( subheap
, (char *)(pArena
+ 1) + size
,
502 (pArena
->size
& ARENA_SIZE_MASK
) - size
);
503 /* assign size plus previous arena flags */
504 pArena
->size
= size
| (pArena
->size
& ~ARENA_SIZE_MASK
);
508 /* Turn off PREV_FREE flag in next block */
509 char *pNext
= (char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
);
510 if (pNext
< (char *)subheap
+ subheap
->size
)
511 *(PULONG
)pNext
&= ~ARENA_FLAG_PREV_FREE
;
515 /***********************************************************************
518 static BOOLEAN
HEAP_InitSubHeap( HEAP
*heap
, PVOID address
, ULONG flags
,
519 ULONG commitSize
, ULONG totalSize
,
520 PRTL_HEAP_PARAMETERS Parameters
)
522 SUBHEAP
*subheap
= (SUBHEAP
*)address
;
523 FREE_LIST_ENTRY
*pEntry
;
527 /* Fill the sub-heap structure */
529 subheap
= (PSUBHEAP
)address
;
530 subheap
->heap
= heap
;
531 subheap
->size
= totalSize
;
532 subheap
->commitSize
= commitSize
;
533 subheap
->magic
= SUBHEAP_MAGIC
;
535 if ( subheap
!= (SUBHEAP
*)heap
)
537 /* If this is a secondary subheap, insert it into list */
539 subheap
->headerSize
= sizeof(SUBHEAP
);
540 subheap
->next
= heap
->subheap
.next
;
541 heap
->subheap
.next
= subheap
;
545 /* If this is a primary subheap, initialize main heap */
547 subheap
->headerSize
= sizeof(HEAP
);
548 subheap
->next
= NULL
;
551 heap
->magic
= HEAP_MAGIC
;
553 heap
->commitRoutine
= Parameters
->CommitRoutine
;
555 heap
->commitRoutine
= NULL
;
557 /* Build the free lists */
559 for (i
= 0, pEntry
= heap
->freeList
; i
< HEAP_NB_FREE_LISTS
; i
++, pEntry
++)
561 pEntry
->size
= HEAP_freeListSizes
[i
];
562 pEntry
->arena
.size
= 0 | ARENA_FLAG_FREE
;
563 pEntry
->arena
.next
= i
< HEAP_NB_FREE_LISTS
-1 ?
564 &heap
->freeList
[i
+1].arena
: &heap
->freeList
[0].arena
;
565 pEntry
->arena
.prev
= i
? &heap
->freeList
[i
-1].arena
:
566 &heap
->freeList
[HEAP_NB_FREE_LISTS
-1].arena
;
567 pEntry
->arena
.threadId
= 0;
568 pEntry
->arena
.magic
= ARENA_FREE_MAGIC
;
571 /* Initialize critical section */
573 RtlInitializeHeapLock( &heap
->critSection
);
577 if (heap
->commitRoutine
)
579 Status
= heap
->commitRoutine(heap
, &address
, &commitSize
);
583 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
588 PAGE_EXECUTE_READWRITE
);
590 if (!NT_SUCCESS(Status
))
592 DPRINT("Could not commit %08lx bytes for sub-heap %p\n",
593 commitSize
, address
);
597 /* Create the first free block */
599 HEAP_CreateFreeBlock( subheap
, (PUCHAR
)subheap
+ subheap
->headerSize
,
600 subheap
->size
- subheap
->headerSize
);
605 /***********************************************************************
608 * Create a sub-heap of the given size.
609 * If heap == NULL, creates a main heap.
612 HEAP_CreateSubHeap(PVOID BaseAddress
,
613 HEAP
*heap
, ULONG flags
,
614 ULONG commitSize
, ULONG totalSize
,
615 PRTL_HEAP_PARAMETERS Parameters
)
620 /* Round-up sizes on a 64K boundary */
622 totalSize
= (totalSize
+ 0xffff) & 0xffff0000;
623 commitSize
= (commitSize
+ 0xffff) & 0xffff0000;
625 commitSize
= 0x10000;
626 if (totalSize
< commitSize
)
627 totalSize
= commitSize
;
629 /* Allocate the memory block */
630 address
= BaseAddress
;
633 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
637 MEM_RESERVE
| MEM_COMMIT
,
638 PAGE_EXECUTE_READWRITE
);
639 if (!NT_SUCCESS(Status
))
641 DPRINT("Could not VirtualAlloc %08lx bytes\n",
647 /* Initialize subheap */
649 if (!HEAP_InitSubHeap( heap
? heap
: (HEAP
*)address
,
650 address
, flags
, commitSize
, totalSize
,
656 ZwFreeVirtualMemory(NtCurrentProcess(),
664 return (SUBHEAP
*)address
;
668 /***********************************************************************
671 * Find a free block at least as large as the requested size, and make sure
672 * the requested size is committed.
674 static ARENA_FREE
*HEAP_FindFreeBlock( HEAP
*heap
, ULONG size
,
675 SUBHEAP
**ppSubHeap
)
679 FREE_LIST_ENTRY
*pEntry
= heap
->freeList
;
681 /* Find a suitable free list, and in it find a block large enough */
683 while (pEntry
->size
< size
)
685 pArena
= pEntry
->arena
.next
;
686 while (pArena
!= &heap
->freeList
[0].arena
)
688 ULONG arena_size
= (pArena
->size
& ARENA_SIZE_MASK
) +
689 sizeof(ARENA_FREE
) - sizeof(ARENA_INUSE
);
690 if (arena_size
>= size
)
692 subheap
= HEAP_FindSubHeap( heap
, pArena
);
693 if (!HEAP_Commit( subheap
, (char *)pArena
+ sizeof(ARENA_INUSE
)
694 + size
+ HEAP_MIN_BLOCK_SIZE
,
697 *ppSubHeap
= subheap
;
701 pArena
= pArena
->next
;
704 /* If no block was found, attempt to grow the heap */
706 if (!(heap
->flags
& HEAP_GROWABLE
))
708 DPRINT("Not enough space in heap %p for %08lx bytes\n",
712 /* make sure that we have a big enough size *committed* to fit another
713 * last free arena in !
714 * So just one heap struct, one first free arena which will eventually
715 * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
716 * might get assigned all remaining free space in HEAP_ShrinkBlock() */
717 size
+= sizeof(SUBHEAP
) + sizeof(ARENA_FREE
) + HEAP_MIN_BLOCK_SIZE
;
718 if (!(subheap
= HEAP_CreateSubHeap( NULL
, heap
, heap
->flags
, size
,
719 max( HEAP_DEF_SIZE
, size
), NULL
)))
722 DPRINT("created new sub-heap %p of %08lx bytes for heap %p\n",
723 subheap
, size
, heap
);
725 *ppSubHeap
= subheap
;
726 return (ARENA_FREE
*)(subheap
+ 1);
730 /***********************************************************************
731 * HEAP_IsValidArenaPtr
733 * Check that the pointer is inside the range possible for arenas.
735 static BOOLEAN
HEAP_IsValidArenaPtr( HEAP
*heap
, PVOID ptr
)
738 SUBHEAP
*subheap
= HEAP_FindSubHeap( heap
, ptr
);
741 if ((char *)ptr
>= (char *)subheap
+ subheap
->headerSize
)
743 if (subheap
!= &heap
->subheap
)
745 for (i
= 0; i
< HEAP_NB_FREE_LISTS
; i
++)
746 if (ptr
== (PVOID
)&heap
->freeList
[i
].arena
)
752 /***********************************************************************
753 * HEAP_ValidateFreeArena
755 static BOOLEAN
HEAP_ValidateFreeArena( SUBHEAP
*subheap
, ARENA_FREE
*pArena
)
757 char *heapEnd
= (char *)subheap
+ subheap
->size
;
759 /* Check magic number */
760 if (pArena
->magic
!= ARENA_FREE_MAGIC
)
762 DPRINT("Heap %p: invalid free arena magic for %p\n",
763 subheap
->heap
, pArena
);
766 /* Check size flags */
767 if (!(pArena
->size
& ARENA_FLAG_FREE
) ||
768 (pArena
->size
& ARENA_FLAG_PREV_FREE
))
770 DPRINT("Heap %p: bad flags %lx for free arena %p\n",
771 subheap
->heap
, pArena
->size
& ~ARENA_SIZE_MASK
, pArena
);
773 /* Check arena size */
774 if ((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) > heapEnd
)
776 DPRINT("Heap %p: bad size %08lx for free arena %p\n",
777 subheap
->heap
, (ULONG
)pArena
->size
& ARENA_SIZE_MASK
, pArena
);
780 /* Check that next pointer is valid */
781 if (!HEAP_IsValidArenaPtr( subheap
->heap
, pArena
->next
))
783 DPRINT("Heap %p: bad next ptr %p for arena %p\n",
784 subheap
->heap
, pArena
->next
, pArena
);
787 /* Check that next arena is free */
788 if (!(pArena
->next
->size
& ARENA_FLAG_FREE
) ||
789 (pArena
->next
->magic
!= ARENA_FREE_MAGIC
))
791 DPRINT("Heap %p: next arena %p invalid for %p\n",
792 subheap
->heap
, pArena
->next
, pArena
);
795 /* Check that prev pointer is valid */
796 if (!HEAP_IsValidArenaPtr( subheap
->heap
, pArena
->prev
))
798 DPRINT("Heap %p: bad prev ptr %p for arena %p\n",
799 subheap
->heap
, pArena
->prev
, pArena
);
802 /* Check that prev arena is free */
803 if (!(pArena
->prev
->size
& ARENA_FLAG_FREE
) ||
804 (pArena
->prev
->magic
!= ARENA_FREE_MAGIC
))
806 DPRINT("Heap %p: prev arena %p invalid for %p\n",
807 subheap
->heap
, pArena
->prev
, pArena
);
810 /* Check that next block has PREV_FREE flag */
811 if ((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) < heapEnd
)
813 if (!(*(PULONG
)((char *)(pArena
+ 1) +
814 (pArena
->size
& ARENA_SIZE_MASK
)) & ARENA_FLAG_PREV_FREE
))
816 DPRINT("Heap %p: free arena %p next block has no PREV_FREE flag\n",
817 subheap
->heap
, pArena
);
820 /* Check next block back pointer */
821 if (*((ARENA_FREE
**)((char *)(pArena
+ 1) +
822 (pArena
->size
& ARENA_SIZE_MASK
)) - 1) != pArena
)
824 DPRINT("Heap %p: arena %p has wrong back ptr %p\n",
825 subheap
->heap
, pArena
,
826 *((PULONG
)((char *)(pArena
+1)+ (pArena
->size
& ARENA_SIZE_MASK
)) - 1));
834 /***********************************************************************
835 * HEAP_ValidateInUseArena
837 static BOOLEAN
HEAP_ValidateInUseArena( SUBHEAP
*subheap
, ARENA_INUSE
*pArena
, BOOLEAN quiet
)
839 char *heapEnd
= (char *)subheap
+ subheap
->size
;
841 /* Check magic number */
842 if (pArena
->magic
!= ARENA_INUSE_MAGIC
)
846 DPRINT("Heap %p: invalid in-use arena magic for %p\n",
847 subheap
->heap
, pArena
);
849 HEAP_Dump( subheap
->heap
);
851 else if (WARN_ON(heap
))
853 DPRINT("Heap %p: invalid in-use arena magic for %p\n",
854 subheap
->heap
, pArena
);
856 HEAP_Dump( subheap
->heap
);
860 /* Check size flags */
861 if (pArena
->size
& ARENA_FLAG_FREE
)
863 DPRINT("Heap %p: bad flags %lx for in-use arena %p\n",
864 subheap
->heap
, pArena
->size
& ~ARENA_SIZE_MASK
, pArena
);
867 /* Check arena size */
868 if ((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) > heapEnd
)
870 DPRINT("Heap %p: bad size %08lx for in-use arena %p\n",
871 subheap
->heap
, (ULONG
)pArena
->size
& ARENA_SIZE_MASK
, pArena
);
874 /* Check next arena PREV_FREE flag */
875 if (((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) < heapEnd
) &&
876 (*(PULONG
)((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
)) & ARENA_FLAG_PREV_FREE
))
878 DPRINT("Heap %p: in-use arena %p next block has PREV_FREE flag\n",
879 subheap
->heap
, pArena
);
882 /* Check prev free arena */
883 if (pArena
->size
& ARENA_FLAG_PREV_FREE
)
885 ARENA_FREE
*pPrev
= *((ARENA_FREE
**)pArena
- 1);
886 /* Check prev pointer */
887 if (!HEAP_IsValidArenaPtr( subheap
->heap
, pPrev
))
889 DPRINT("Heap %p: bad back ptr %p for arena %p\n",
890 subheap
->heap
, pPrev
, pArena
);
893 /* Check that prev arena is free */
894 if (!(pPrev
->size
& ARENA_FLAG_FREE
) ||
895 (pPrev
->magic
!= ARENA_FREE_MAGIC
))
897 DPRINT("Heap %p: prev arena %p invalid for in-use %p\n",
898 subheap
->heap
, pPrev
, pArena
);
901 /* Check that prev arena is really the previous block */
902 if ((char *)(pPrev
+ 1) + (pPrev
->size
& ARENA_SIZE_MASK
) != (char *)pArena
)
904 DPRINT("Heap %p: prev arena %p is not prev for in-use %p\n",
905 subheap
->heap
, pPrev
, pArena
);
913 /***********************************************************************
915 * Checks whether the pointer points to a block inside a given heap.
918 * Should this return BOOL32?
924 int HEAP_IsInsideHeap(
925 HANDLE heap
, /* [in] Heap */
926 ULONG flags
, /* [in] Flags */
927 PVOID ptr
/* [in] Pointer */
930 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
934 /* Validate the parameters */
938 flags
|= heapPtr
->flags
;
939 if (!(flags
& HEAP_NO_SERIALIZE
))
940 RtlEnterHeapLock( &heapPtr
->critSection
);
941 ret
= (((subheap
= HEAP_FindSubHeap( heapPtr
, ptr
)) != NULL
) &&
942 (((char *)ptr
>= (char *)subheap
+ subheap
->headerSize
943 + sizeof(ARENA_INUSE
))));
944 if (!(flags
& HEAP_NO_SERIALIZE
))
945 RtlLeaveHeapLock( &heapPtr
->critSection
);
950 void DumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
954 DbgPrint("Frames: ");
958 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
959 #elif defined(_MSC_VER)
960 __asm mov
[Frame
], ebp
962 Frame
= (PULONG
)Frame
[0]; // step out of DumpStackFrames
964 while ( Frame
!= 0 && (ULONG
)Frame
!= 0xDEADBEEF && (ULONG
)Frame
!= 0xcdcdcdcd && (ULONG
)Frame
!= 0xcccccccc && i
++ < FrameCount
)
966 DbgPrint("<%p>", (PVOID
)Frame
[1]);
967 if (Frame
[1] == 0xdeadbeef)
969 Frame
= (PULONG
)Frame
[0];
975 /***********************************************************************
976 * HEAP_IsRealArena [Internal]
977 * Validates a block is a valid arena.
983 static BOOLEAN
HEAP_IsRealArena(
984 HANDLE heap
, /* [in] Handle to the heap */
985 ULONG flags
, /* [in] Bit flags that control access during operation */
986 PVOID block
, /* [in] Optional pointer to memory block to validate */
987 BOOLEAN quiet
/* [in] Flag - if true, HEAP_ValidateInUseArena
988 * does not complain */
992 HEAP
*heapPtr
= (HEAP
*)(heap
);
995 if (!heapPtr
|| (heapPtr
->magic
!= HEAP_MAGIC
))
997 DPRINT("Invalid heap %08x!\n", heap
);
1001 flags
&= HEAP_NO_SERIALIZE
;
1002 flags
|= heapPtr
->flags
;
1003 /* calling HeapLock may result in infinite recursion, so do the critsect directly */
1004 if (!(flags
& HEAP_NO_SERIALIZE
))
1005 RtlEnterHeapLock( &heapPtr
->critSection
);
1009 /* Only check this single memory block */
1011 /* The following code is really HEAP_IsInsideHeap *
1012 * with serialization already done. */
1013 if (!(subheap
= HEAP_FindSubHeap( heapPtr
, block
)) ||
1014 ((char *)block
< (char *)subheap
+ subheap
->headerSize
1015 + sizeof(ARENA_INUSE
)))
1019 DPRINT("Heap %p: block %p is not inside heap\n",
1021 DumpStackFrames(NULL
,10);
1023 else if (WARN_ON(heap
))
1025 DPRINT1("Heap %p: block %p is not inside heap\n",
1027 DumpStackFrames(NULL
,10);
1032 ret
= HEAP_ValidateInUseArena( subheap
, (ARENA_INUSE
*)block
- 1, quiet
);
1034 if (!(flags
& HEAP_NO_SERIALIZE
))
1035 RtlLeaveHeapLock( &heapPtr
->critSection
);
1039 subheap
= &heapPtr
->subheap
;
1040 while (subheap
&& ret
)
1042 char *ptr
= (char *)subheap
+ subheap
->headerSize
;
1043 while (ptr
< (char *)subheap
+ subheap
->size
)
1045 if (*(PULONG
)ptr
& ARENA_FLAG_FREE
)
1047 if (!HEAP_ValidateFreeArena( subheap
, (ARENA_FREE
*)ptr
))
1052 ptr
+= sizeof(ARENA_FREE
) + (*(PULONG
)ptr
& ARENA_SIZE_MASK
);
1056 if (!HEAP_ValidateInUseArena( subheap
, (ARENA_INUSE
*)ptr
, NOISY
))
1061 ptr
+= sizeof(ARENA_INUSE
) + (*(PULONG
)ptr
& ARENA_SIZE_MASK
);
1064 subheap
= subheap
->next
;
1067 if (!(flags
& HEAP_NO_SERIALIZE
))
1068 RtlLeaveHeapLock( &heapPtr
->critSection
);
1073 /***********************************************************************
1074 * HeapCreate (KERNEL32.336)
1076 * Handle of heap: Success
1082 RtlCreateHeap(ULONG flags
,
1087 PRTL_HEAP_PARAMETERS Parameters
)
1092 /* Allocate the heap block */
1096 maxSize
= HEAP_DEF_SIZE
;
1097 flags
|= HEAP_GROWABLE
;
1099 if (!(subheap
= HEAP_CreateSubHeap( BaseAddress
, NULL
, flags
, initialSize
,
1100 maxSize
, Parameters
)))
1105 if (RtlpGetMode() == UserMode
)
1107 /* link it into the per-process heap list */
1108 RtlEnterHeapLock (&RtlpProcessHeapsListLock
);
1110 heapPtr
= subheap
->heap
;
1111 heapPtr
->next
= (HEAP
*)NtCurrentPeb()->ProcessHeaps
;
1112 NtCurrentPeb()->ProcessHeaps
= (HANDLE
)heapPtr
;
1113 NtCurrentPeb()->NumberOfHeaps
++;
1115 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1118 return (HANDLE
)subheap
;
1121 /***********************************************************************
1122 * HeapDestroy (KERNEL32.337)
1130 * Success: A NULL HANDLE, if heap is NULL or it was destroyed
1131 * Failure: The Heap handle, if heap is the process heap.
1134 RtlDestroyHeap(HANDLE heap
) /* [in] Handle of heap */
1136 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
1141 DPRINT("%08x\n", heap
);
1145 if (RtlpGetMode() == UserMode
)
1147 if (heap
== NtCurrentPeb()->ProcessHeap
)
1148 return heap
; /* cannot delete the main process heap */
1150 /* remove it from the per-process list */
1151 RtlEnterHeapLock (&RtlpProcessHeapsListLock
);
1153 pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
;
1154 while (*pptr
&& *pptr
!= heapPtr
) pptr
= &(*pptr
)->next
;
1155 if (*pptr
) *pptr
= (*pptr
)->next
;
1156 NtCurrentPeb()->NumberOfHeaps
--;
1158 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1161 RtlDeleteHeapLock( &heapPtr
->critSection
);
1162 subheap
= &heapPtr
->subheap
;
1163 // We must save the flags. The first subheap is located after
1164 // the heap structure. If we release the first subheap,
1165 // we release also the heap structure.
1166 flags
= heapPtr
->flags
;
1169 SUBHEAP
*next
= subheap
->next
;
1170 ULONG dummySize
= 0;
1171 ZwFreeVirtualMemory(NtCurrentProcess(),
1177 return (HANDLE
)NULL
;
1181 /***********************************************************************
1182 * HeapAlloc (KERNEL32.334)
1184 * Pointer to allocated memory block
1186 * 0x7d030f60--invalid flags in RtlHeapAllocate
1190 RtlAllocateHeap(HANDLE heap
, /* [in] Handle of private heap block */
1191 ULONG flags
, /* [in] Heap allocation control flags */
1192 ULONG size
) /* [in] Number of bytes to allocate */
1195 ARENA_INUSE
*pInUse
;
1197 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
1199 /* Validate the parameters */
1203 if (flags
& HEAP_GENERATE_EXCEPTIONS
)
1204 RtlRaiseStatus( STATUS_NO_MEMORY
);
1207 flags
&= HEAP_GENERATE_EXCEPTIONS
| HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
;
1208 flags
|= heapPtr
->flags
;
1209 if (!(flags
& HEAP_NO_SERIALIZE
))
1210 RtlEnterHeapLock( &heapPtr
->critSection
);
1211 size
= (size
+ 7) & ~7;
1212 if (size
< HEAP_MIN_BLOCK_SIZE
)
1213 size
= HEAP_MIN_BLOCK_SIZE
;
1215 /* Locate a suitable free block */
1217 if (!(pArena
= HEAP_FindFreeBlock( heapPtr
, size
, &subheap
)))
1219 DPRINT("(%08x,%08lx,%08lx): returning NULL\n",
1220 heap
, flags
, size
);
1221 if (!(flags
& HEAP_NO_SERIALIZE
))
1222 RtlLeaveHeapLock( &heapPtr
->critSection
);
1223 if (flags
& HEAP_GENERATE_EXCEPTIONS
)
1224 RtlRaiseStatus( STATUS_NO_MEMORY
);
1228 /* Remove the arena from the free list */
1230 pArena
->next
->prev
= pArena
->prev
;
1231 pArena
->prev
->next
= pArena
->next
;
1233 /* Build the in-use arena */
1235 pInUse
= (ARENA_INUSE
*)pArena
;
1236 pInUse
->size
= (pInUse
->size
& ~ARENA_FLAG_FREE
)
1237 + sizeof(ARENA_FREE
) - sizeof(ARENA_INUSE
);
1238 pInUse
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
1239 pInUse
->magic
= ARENA_INUSE_MAGIC
;
1241 /* Shrink the block */
1243 HEAP_ShrinkBlock( subheap
, pInUse
, size
);
1245 if (flags
& HEAP_ZERO_MEMORY
)
1246 memset( pInUse
+ 1, 0, pInUse
->size
& ARENA_SIZE_MASK
);
1247 else if (TRACE_ON(heap
))
1248 memset( pInUse
+ 1, ARENA_INUSE_FILLER
, pInUse
->size
& ARENA_SIZE_MASK
);
1250 if (!(flags
& HEAP_NO_SERIALIZE
))
1251 RtlLeaveHeapLock( &heapPtr
->critSection
);
1253 DPRINT("(%08x,%08lx,%08lx): returning %p\n",
1254 heap
, flags
, size
, (PVOID
)(pInUse
+ 1) );
1255 return (PVOID
)(pInUse
+ 1);
1259 /***********************************************************************
1260 * HeapFree (KERNEL32.338)
1267 BOOLEAN NTAPI
RtlFreeHeap(
1268 HANDLE heap
, /* [in] Handle of heap */
1269 ULONG flags
, /* [in] Heap freeing flags */
1270 PVOID ptr
/* [in] Address of memory to free */
1273 ARENA_INUSE
*pInUse
;
1275 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
1277 /* Validate the parameters */
1281 if (!ptr
) /* Freeing a NULL ptr is doesn't indicate an error in Win2k */
1283 DPRINT("(%08x,%08lx,%p): asked to free NULL\n",
1288 flags
&= HEAP_NO_SERIALIZE
;
1289 flags
|= heapPtr
->flags
;
1290 if (!(flags
& HEAP_NO_SERIALIZE
))
1291 RtlEnterHeapLock( &heapPtr
->critSection
);
1292 if (!HEAP_IsRealArena( heap
, HEAP_NO_SERIALIZE
, ptr
, QUIET
))
1294 if (!(flags
& HEAP_NO_SERIALIZE
))
1295 RtlLeaveHeapLock( &heapPtr
->critSection
);
1296 DPRINT("(%08x,%08lx,%p): returning FALSE\n",
1301 /* Turn the block into a free block */
1303 pInUse
= (ARENA_INUSE
*)ptr
- 1;
1304 subheap
= HEAP_FindSubHeap( heapPtr
, pInUse
);
1305 HEAP_MakeInUseBlockFree( subheap
, pInUse
, heapPtr
->flags
);
1307 if (!(flags
& HEAP_NO_SERIALIZE
))
1308 RtlLeaveHeapLock( &heapPtr
->critSection
);
1310 DPRINT("(%08x,%08lx,%p): returning TRUE\n",
1316 /***********************************************************************
1319 * Heap [in] Handle of heap block
1320 * Flags [in] Heap reallocation flags
1321 * Ptr, [in] Address of memory to reallocate
1322 * Size [in] Number of bytes to reallocate
1325 * Pointer to reallocated memory block
1327 * 0x7d030f60--invalid flags in RtlHeapAllocate
1330 PVOID NTAPI
RtlReAllocateHeap(
1337 ARENA_INUSE
*pArena
;
1344 if (!(heapPtr
= HEAP_GetPtr( Heap
)))
1347 /* Validate the parameters */
1349 Flags
&= HEAP_GENERATE_EXCEPTIONS
| HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
|
1350 HEAP_REALLOC_IN_PLACE_ONLY
;
1351 Flags
|= heapPtr
->flags
;
1352 Size
= (Size
+ 7) & ~7;
1353 if (Size
< HEAP_MIN_BLOCK_SIZE
)
1354 Size
= HEAP_MIN_BLOCK_SIZE
;
1356 if (!(Flags
& HEAP_NO_SERIALIZE
))
1357 RtlEnterHeapLock( &heapPtr
->critSection
);
1358 if (!HEAP_IsRealArena( Heap
, HEAP_NO_SERIALIZE
, Ptr
, QUIET
))
1360 if (!(Flags
& HEAP_NO_SERIALIZE
))
1361 RtlLeaveHeapLock( &heapPtr
->critSection
);
1362 DPRINT("(%08x,%08lx,%p,%08lx): returning NULL\n",
1363 Heap
, Flags
, Ptr
, Size
);
1364 if (Flags
& HEAP_GENERATE_EXCEPTIONS
)
1365 RtlRaiseStatus( STATUS_NO_MEMORY
);
1369 /* Check if we need to grow the block */
1371 pArena
= (ARENA_INUSE
*)Ptr
- 1;
1372 pArena
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
1374 subheap
= HEAP_FindSubHeap( heapPtr
, pArena
);
1375 oldSize
= (pArena
->size
& ARENA_SIZE_MASK
);
1378 char *pNext
= (char *)(pArena
+ 1) + oldSize
;
1379 if ((pNext
< (char *)subheap
+ subheap
->size
) &&
1380 (*(PULONG
)pNext
& ARENA_FLAG_FREE
) &&
1381 (oldSize
+ (*(PULONG
)pNext
& ARENA_SIZE_MASK
) + sizeof(ARENA_FREE
) >= Size
))
1383 /* The next block is free and large enough */
1384 ARENA_FREE
*pFree
= (ARENA_FREE
*)pNext
;
1385 pFree
->next
->prev
= pFree
->prev
;
1386 pFree
->prev
->next
= pFree
->next
;
1387 pArena
->size
+= (pFree
->size
& ARENA_SIZE_MASK
) + sizeof(*pFree
);
1388 if (!HEAP_Commit( subheap
, (char *)pArena
+ sizeof(ARENA_INUSE
)
1389 + Size
+ HEAP_MIN_BLOCK_SIZE
,
1392 if (!(Flags
& HEAP_NO_SERIALIZE
))
1393 RtlLeaveHeapLock( &heapPtr
->critSection
);
1394 if (Flags
& HEAP_GENERATE_EXCEPTIONS
)
1395 RtlRaiseStatus( STATUS_NO_MEMORY
);
1398 HEAP_ShrinkBlock( subheap
, pArena
, Size
);
1400 else /* Do it the hard way */
1403 ARENA_INUSE
*pInUse
;
1404 SUBHEAP
*newsubheap
;
1406 if ((Flags
& HEAP_REALLOC_IN_PLACE_ONLY
) ||
1407 !(pNew
= HEAP_FindFreeBlock( heapPtr
, Size
, &newsubheap
)))
1409 if (!(Flags
& HEAP_NO_SERIALIZE
))
1410 RtlLeaveHeapLock( &heapPtr
->critSection
);
1411 if (Flags
& HEAP_GENERATE_EXCEPTIONS
)
1412 RtlRaiseStatus( STATUS_NO_MEMORY
);
1416 /* Build the in-use arena */
1418 pNew
->next
->prev
= pNew
->prev
;
1419 pNew
->prev
->next
= pNew
->next
;
1420 pInUse
= (ARENA_INUSE
*)pNew
;
1421 pInUse
->size
= (pInUse
->size
& ~ARENA_FLAG_FREE
)
1422 + sizeof(ARENA_FREE
) - sizeof(ARENA_INUSE
);
1423 pInUse
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
1424 pInUse
->magic
= ARENA_INUSE_MAGIC
;
1425 HEAP_ShrinkBlock( newsubheap
, pInUse
, Size
);
1426 memcpy( pInUse
+ 1, pArena
+ 1, oldSize
);
1428 /* Free the previous block */
1430 HEAP_MakeInUseBlockFree( subheap
, pArena
, Flags
);
1431 subheap
= newsubheap
;
1436 HEAP_ShrinkBlock( subheap
, pArena
, Size
); /* Shrink the block */
1438 /* Clear the extra bytes if needed */
1442 if (Flags
& HEAP_ZERO_MEMORY
)
1443 memset( (char *)(pArena
+ 1) + oldSize
, 0,
1444 (pArena
->size
& ARENA_SIZE_MASK
) - oldSize
);
1445 else if (TRACE_ON(heap
))
1446 memset( (char *)(pArena
+ 1) + oldSize
, ARENA_INUSE_FILLER
,
1447 (pArena
->size
& ARENA_SIZE_MASK
) - oldSize
);
1450 /* Return the new arena */
1452 if (!(Flags
& HEAP_NO_SERIALIZE
))
1453 RtlLeaveHeapLock( &heapPtr
->critSection
);
1455 DPRINT("(%08x,%08lx,%p,%08lx): returning %p\n",
1456 Heap
, Flags
, Ptr
, Size
, (PVOID
)(pArena
+ 1) );
1457 return (PVOID
)(pArena
+ 1);
1461 /***********************************************************************
1467 RtlCompactHeap(HANDLE Heap
,
1475 /***********************************************************************
1477 * Attempts to acquire the critical section object for a specified heap.
1480 * Heap [in] Handle of heap to lock for exclusive access
1489 RtlLockHeap(IN HANDLE Heap
)
1491 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1494 RtlEnterHeapLock( &heapPtr
->critSection
);
1499 /***********************************************************************
1501 * Releases ownership of the critical section object.
1504 * Heap [in] Handle to the heap to unlock
1513 RtlUnlockHeap(HANDLE Heap
)
1515 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1518 RtlLeaveHeapLock( &heapPtr
->critSection
);
1523 /***********************************************************************
1526 * Heap [in] Handle of heap
1527 * Flags [in] Heap size control flags
1528 * Ptr [in] Address of memory to return size for
1531 * Size in bytes of allocated memory
1532 * 0xffffffff: Failure
1544 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1548 Flags
&= HEAP_NO_SERIALIZE
;
1549 Flags
|= heapPtr
->flags
;
1550 if (!(Flags
& HEAP_NO_SERIALIZE
))
1551 RtlEnterHeapLock( &heapPtr
->critSection
);
1552 if (!HEAP_IsRealArena( Heap
, HEAP_NO_SERIALIZE
, Ptr
, QUIET
))
1558 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)Ptr
- 1;
1559 ret
= pArena
->size
& ARENA_SIZE_MASK
;
1561 if (!(Flags
& HEAP_NO_SERIALIZE
))
1562 RtlLeaveHeapLock( &heapPtr
->critSection
);
1564 DPRINT("(%08x,%08lx,%p): returning %08lx\n",
1565 Heap
, Flags
, Ptr
, ret
);
1570 /***********************************************************************
1572 * Validates a specified heap.
1575 * Heap [in] Handle to the heap
1576 * Flags [in] Bit flags that control access during operation
1577 * Block [in] Optional pointer to memory block to validate
1588 BOOLEAN NTAPI
RtlValidateHeap(
1594 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1597 return HEAP_IsRealArena( heapPtr
, Flags
, Block
, QUIET
);
1601 /***********************************************************************
1602 * HeapWalk (KERNEL32.344)
1603 * Enumerates the memory blocks in a specified heap.
1604 * See HEAP_Dump() for info on heap structure.
1607 * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
1608 * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
1615 BOOLEAN NTAPI
HeapWalk(
1616 HANDLE heap
, /* [in] Handle to heap to enumerate */
1617 LPPROCESS_HEAP_ENTRY entry
/* [out] Pointer to structure of enumeration info */
1620 HEAP
*heapPtr
= HEAP_GetPtr(heap
);
1621 SUBHEAP
*sub
, *currentheap
= NULL
;
1622 BOOLEAN ret
= FALSE
;
1624 int region_index
= 0;
1626 if (!heapPtr
|| !entry
)
1631 if (!(heapPtr
->flags
& HEAP_NO_SERIALIZE
))
1632 RtlEnterHeapLock( &heapPtr
->critSection
);
1634 /* set ptr to the next arena to be examined */
1636 if (!entry
->lpData
) /* first call (init) ? */
1638 DPRINT("begin walking of heap 0x%08x.\n", heap
);
1639 /*HEAP_Dump(heapPtr);*/
1640 currentheap
= &heapPtr
->subheap
;
1641 ptr
= (char*)currentheap
+ currentheap
->headerSize
;
1645 ptr
= entry
->lpData
;
1646 sub
= &heapPtr
->subheap
;
1649 if (((char *)ptr
>= (char *)sub
) &&
1650 ((char *)ptr
< (char *)sub
+ sub
->size
))
1658 if (currentheap
== NULL
)
1660 DPRINT("no matching subheap found, shouldn't happen !\n");
1664 ptr
+= entry
->cbData
; /* point to next arena */
1665 if (ptr
> (char *)currentheap
+ currentheap
->size
- 1)
1666 { /* proceed with next subheap */
1667 if (!(currentheap
= currentheap
->next
))
1668 { /* successfully finished */
1669 DPRINT("end reached.\n");
1672 ptr
= (char*)currentheap
+ currentheap
->headerSize
;
1677 if (*(PULONG
)ptr
& ARENA_FLAG_FREE
)
1679 ARENA_FREE
*pArena
= (ARENA_FREE
*)ptr
;
1681 /*DPRINT("free, magic: %04x\n", pArena->magic);*/
1683 entry
->lpData
= pArena
+ 1;
1684 entry
->cbData
= pArena
->size
& ARENA_SIZE_MASK
;
1685 entry
->cbOverhead
= sizeof(ARENA_FREE
);
1686 entry
->wFlags
= PROCESS_HEAP_UNCOMMITTED_RANGE
;
1690 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)ptr
;
1692 /*DPRINT("busy, magic: %04x\n", pArena->magic);*/
1694 entry
->lpData
= pArena
+ 1;
1695 entry
->cbData
= pArena
->size
& ARENA_SIZE_MASK
;
1696 entry
->cbOverhead
= sizeof(ARENA_INUSE
);
1697 entry
->wFlags
= PROCESS_HEAP_ENTRY_BUSY
;
1698 /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
1699 and PROCESS_HEAP_ENTRY_DDESHARE yet */
1702 entry
->iRegionIndex
= region_index
;
1704 /* first element of heap ? */
1705 if (ptr
== (char *)(currentheap
+ currentheap
->headerSize
))
1707 entry
->wFlags
|= PROCESS_HEAP_REGION
;
1708 entry
->Foo
.Region
.dwCommittedSize
= currentheap
->commitSize
;
1709 entry
->Foo
.Region
.dwUnCommittedSize
=
1710 currentheap
->size
- currentheap
->commitSize
;
1711 entry
->Foo
.Region
.lpFirstBlock
= /* first valid block */
1712 currentheap
+ currentheap
->headerSize
;
1713 entry
->Foo
.Region
.lpLastBlock
= /* first invalid block */
1714 currentheap
+ currentheap
->size
;
1719 if (!(heapPtr
->flags
& HEAP_NO_SERIALIZE
))
1720 RtlLeaveHeapLock( &heapPtr
->critSection
);
1728 RtlInitializeHeapManager(VOID
)
1732 Peb
= NtCurrentPeb();
1734 Peb
->NumberOfHeaps
= 0;
1735 Peb
->MaximumNumberOfHeaps
= -1; /* no limit */
1736 Peb
->ProcessHeaps
= NULL
;
1738 RtlInitializeHeapLock(&RtlpProcessHeapsListLock
);
1746 RtlEnumProcessHeaps(PHEAP_ENUMERATION_ROUTINE HeapEnumerationRoutine
,
1749 NTSTATUS Status
= STATUS_SUCCESS
;
1752 RtlEnterHeapLock(&RtlpProcessHeapsListLock
);
1754 for (pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
; *pptr
; pptr
= &(*pptr
)->next
)
1756 Status
= HeapEnumerationRoutine(*pptr
,lParam
);
1757 if (!NT_SUCCESS(Status
))
1761 RtlLeaveHeapLock(&RtlpProcessHeapsListLock
);
1771 RtlGetProcessHeaps(ULONG HeapCount
,
1777 RtlEnterHeapLock(&RtlpProcessHeapsListLock
);
1779 Result
= NtCurrentPeb()->NumberOfHeaps
;
1781 if (NtCurrentPeb()->NumberOfHeaps
<= HeapCount
)
1784 for (pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
; *pptr
; pptr
= &(*pptr
)->next
)
1786 HeapArray
[i
++] = *pptr
;
1790 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1800 RtlValidateProcessHeaps(VOID
)
1802 BOOLEAN Result
= TRUE
;
1805 RtlEnterHeapLock(&RtlpProcessHeapsListLock
);
1807 for (pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
; *pptr
; pptr
= &(*pptr
)->next
)
1809 if (!RtlValidateHeap(*pptr
, 0, NULL
))
1816 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1827 IN PVOID HeapHandle
,