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 */
95 #define SUBHEAP_MAGIC ((ULONG)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
97 typedef struct tagHEAP
99 SUBHEAP subheap
; /* First sub-heap */
100 struct tagHEAP
*next
; /* Next heap for this process */
101 FREE_LIST_ENTRY freeList
[HEAP_NB_FREE_LISTS
]; /* Free lists */
102 RTL_CRITICAL_SECTION critSection
; /* Critical section for serialization */
103 ULONG flags
; /* Heap flags */
104 ULONG magic
; /* Magic number */
105 PRTL_HEAP_COMMIT_ROUTINE commitRoutine
;
109 #define HEAP_MAGIC ((ULONG)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
111 #define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
112 #define HEAP_MIN_BLOCK_SIZE (sizeof(ARENA_FREE) + 8) /* Min. heap block size */
113 #define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */
116 static BOOLEAN
HEAP_IsRealArena( HANDLE heap
, ULONG flags
, PVOID block
, BOOLEAN quiet
);
119 /***********************************************************************
123 HEAP_Dump(PHEAP heap
)
129 DPRINT( "Heap: %p\n", heap
);
130 DPRINT( "Next: %p Sub-heaps: %p",
131 heap
->next
, &heap
->subheap
);
132 subheap
= &heap
->subheap
;
133 while (subheap
->next
)
135 DPRINT( " -> %p", subheap
->next
);
136 subheap
= subheap
->next
;
139 DPRINT( "\nFree lists:\n Block Stat Size Id\n" );
140 for (i
= 0; i
< HEAP_NB_FREE_LISTS
; i
++)
141 DPRINT( "%p free %08lx %04x prev=%p next=%p\n",
142 &heap
->freeList
[i
].arena
,
143 heap
->freeList
[i
].arena
.size
,
144 heap
->freeList
[i
].arena
.threadId
,
145 heap
->freeList
[i
].arena
.prev
,
146 heap
->freeList
[i
].arena
.next
);
148 subheap
= &heap
->subheap
;
151 ULONG freeSize
= 0, usedSize
= 0, arenaSize
= subheap
->headerSize
;
152 DPRINT( "\n\nSub-heap %p: size=%08lx committed=%08lx\n",
153 subheap
, subheap
->size
, subheap
->commitSize
);
155 DPRINT( "\n Block Stat Size Id\n" );
156 ptr
= (char*)subheap
+ subheap
->headerSize
;
157 while (ptr
< (char *)subheap
+ subheap
->size
)
159 if (*(PULONG
)ptr
& ARENA_FLAG_FREE
)
161 ARENA_FREE
*pArena
= (ARENA_FREE
*)ptr
;
162 DPRINT( "%p free %08lx %04x prev=%p next=%p\n",
163 pArena
, pArena
->size
& ARENA_SIZE_MASK
,
164 pArena
->threadId
, pArena
->prev
,
166 ptr
+= sizeof(*pArena
) + (pArena
->size
& ARENA_SIZE_MASK
);
167 arenaSize
+= sizeof(ARENA_FREE
);
168 freeSize
+= pArena
->size
& ARENA_SIZE_MASK
;
170 else if (*(PULONG
)ptr
& ARENA_FLAG_PREV_FREE
)
172 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)ptr
;
173 DPRINT( "%p Used %08lx %04x back=%08lx\n",
174 pArena
, pArena
->size
& ARENA_SIZE_MASK
,
175 pArena
->threadId
, *((PULONG
)pArena
- 1));
176 ptr
+= sizeof(*pArena
) + (pArena
->size
& ARENA_SIZE_MASK
);
177 arenaSize
+= sizeof(ARENA_INUSE
);
178 usedSize
+= pArena
->size
& ARENA_SIZE_MASK
;
182 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)ptr
;
183 DPRINT( "%p used %08lx %04x\n",
184 pArena
, pArena
->size
& ARENA_SIZE_MASK
,
186 ptr
+= sizeof(*pArena
) + (pArena
->size
& ARENA_SIZE_MASK
);
187 arenaSize
+= sizeof(ARENA_INUSE
);
188 usedSize
+= pArena
->size
& ARENA_SIZE_MASK
;
191 DPRINT( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
192 subheap
->size
, subheap
->commitSize
, freeSize
, usedSize
,
193 arenaSize
, (arenaSize
* 100) / subheap
->size
);
194 subheap
= subheap
->next
;
199 /***********************************************************************
202 * Pointer to the heap
206 HEAP_GetPtr(HANDLE heap
) /* [in] Handle to the heap */
208 HEAP
*heapPtr
= (HEAP
*)heap
;
209 if (!heapPtr
|| (heapPtr
->magic
!= HEAP_MAGIC
))
211 DPRINT("Invalid heap %p!\n", heap
);
214 if (TRACE_ON(heap
) && !HEAP_IsRealArena( heap
, 0, NULL
, NOISY
))
216 HEAP_Dump( heapPtr
);
224 /***********************************************************************
225 * HEAP_InsertFreeBlock
227 * Insert a free block into the free list.
230 HEAP_InsertFreeBlock(PHEAP heap
,
234 FREE_LIST_ENTRY
*pEntry
= heap
->freeList
;
235 while (pEntry
->size
< pArena
->size
)
239 /* insert at end of free list, i.e. before next free list entry */
241 if (pEntry
== &heap
->freeList
[HEAP_NB_FREE_LISTS
])
243 pEntry
= heap
->freeList
;
245 pArena
->prev
= pEntry
->arena
.prev
;
246 pArena
->prev
->next
= pArena
;
247 pArena
->next
= &pEntry
->arena
;
248 pEntry
->arena
.prev
= pArena
;
252 /* insert at head of free list */
253 pArena
->next
= pEntry
->arena
.next
;
254 pArena
->next
->prev
= pArena
;
255 pArena
->prev
= &pEntry
->arena
;
256 pEntry
->arena
.next
= pArena
;
258 pArena
->size
|= ARENA_FLAG_FREE
;
262 /***********************************************************************
264 * Find the sub-heap containing a given address.
271 HEAP_FindSubHeap(HEAP
*heap
, /* [in] Heap pointer */
272 PVOID ptr
) /* [in] Address */
274 PSUBHEAP sub
= &heap
->subheap
;
277 if (((char *)ptr
>= (char *)sub
) &&
278 ((char *)ptr
< (char *)sub
+ sub
->size
))
286 /***********************************************************************
289 * Make sure the heap storage is committed up to (not including) ptr.
291 static __inline BOOLEAN
292 HEAP_Commit(SUBHEAP
*subheap
,
296 SIZE_T size
= (SIZE_T
)((char *)ptr
- (char *)subheap
);
301 size
= (size
+ COMMIT_MASK
) & ~COMMIT_MASK
;
302 if (size
> subheap
->size
)
303 size
= subheap
->size
;
304 if (size
<= subheap
->commitSize
)
307 address
= (PVOID
)((char *)subheap
+ subheap
->commitSize
);
308 commitsize
= size
- subheap
->commitSize
;
310 if (subheap
->heap
->commitRoutine
!= NULL
)
312 Status
= subheap
->heap
->commitRoutine(subheap
->heap
, &address
, &commitsize
);
316 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
321 PAGE_EXECUTE_READWRITE
);
323 if (!NT_SUCCESS(Status
))
325 DPRINT( "Could not commit %08lx bytes at %p for heap %p\n",
326 size
- subheap
->commitSize
,
327 ((char *)subheap
+ subheap
->commitSize
),
332 subheap
->commitSize
+= commitsize
;
338 /***********************************************************************
341 * If possible, decommit the heap storage from (including) 'ptr'.
343 static inline BOOLEAN
HEAP_Decommit( SUBHEAP
*subheap
, PVOID ptr
, ULONG flags
)
345 ULONG size
= (ULONG
)((char *)ptr
- (char *)subheap
);
349 /* round to next block and add one full block */
350 size
= ((size
+ COMMIT_MASK
) & ~COMMIT_MASK
) + COMMIT_MASK
+ 1;
351 if (size
>= subheap
->commitSize
)
354 address
= (PVOID
)((char *)subheap
+ size
);
355 decommitsize
= subheap
->commitSize
- size
;
357 Status
= ZwFreeVirtualMemory(NtCurrentProcess(),
361 if (!NT_SUCCESS(Status
))
363 DPRINT( "Could not decommit %08lx bytes at %p for heap %p\n",
364 subheap
->commitSize
- size
,
365 ((char *)subheap
+ size
),
370 subheap
->commitSize
-= decommitsize
;
375 /***********************************************************************
376 * HEAP_CreateFreeBlock
378 * Create a free block at a specified address. 'size' is the size of the
379 * whole block, including the new arena.
381 static VOID
HEAP_CreateFreeBlock( SUBHEAP
*subheap
, PVOID ptr
, ULONG size
)
386 /* Create a free arena */
388 pFree
= (ARENA_FREE
*)ptr
;
389 pFree
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
390 pFree
->magic
= ARENA_FREE_MAGIC
;
392 /* If debugging, erase the freed block content */
396 char *pEnd
= (char *)ptr
+ size
;
397 if (pEnd
> (char *)subheap
+ subheap
->commitSize
)
398 pEnd
= (char *)subheap
+ subheap
->commitSize
;
399 if (pEnd
> (char *)(pFree
+ 1))
400 memset( pFree
+ 1, ARENA_FREE_FILLER
, pEnd
- (char *)(pFree
+ 1) );
403 /* Check if next block is free also */
405 if (((char *)ptr
+ size
< (char *)subheap
+ subheap
->size
) &&
406 (*(PULONG
)((char *)ptr
+ size
) & ARENA_FLAG_FREE
))
408 /* Remove the next arena from the free list */
409 ARENA_FREE
*pNext
= (ARENA_FREE
*)((char *)ptr
+ size
);
410 pNext
->next
->prev
= pNext
->prev
;
411 pNext
->prev
->next
= pNext
->next
;
412 size
+= (pNext
->size
& ARENA_SIZE_MASK
) + sizeof(*pNext
);
414 memset( pNext
, ARENA_FREE_FILLER
, sizeof(ARENA_FREE
) );
417 /* Set the next block PREV_FREE flag and pointer */
419 last
= ((char *)ptr
+ size
>= (char *)subheap
+ subheap
->size
);
422 PULONG pNext
= (PULONG
)((char *)ptr
+ size
);
423 *pNext
|= ARENA_FLAG_PREV_FREE
;
424 *(ARENA_FREE
**)(pNext
- 1) = pFree
;
427 /* Last, insert the new block into the free list */
429 pFree
->size
= size
- sizeof(*pFree
);
430 HEAP_InsertFreeBlock( subheap
->heap
, pFree
, last
);
434 /***********************************************************************
435 * HEAP_MakeInUseBlockFree
437 * Turn an in-use block into a free block. Can also decommit the end of
438 * the heap, and possibly even free the sub-heap altogether.
440 static VOID
HEAP_MakeInUseBlockFree( SUBHEAP
*subheap
, ARENA_INUSE
*pArena
,
444 ULONG size
= (pArena
->size
& ARENA_SIZE_MASK
) + sizeof(*pArena
);
447 /* Check if we can merge with previous block */
449 if (pArena
->size
& ARENA_FLAG_PREV_FREE
)
451 pFree
= *((ARENA_FREE
**)pArena
- 1);
452 size
+= (pFree
->size
& ARENA_SIZE_MASK
) + sizeof(ARENA_FREE
);
453 /* Remove it from the free list */
454 pFree
->next
->prev
= pFree
->prev
;
455 pFree
->prev
->next
= pFree
->next
;
458 pFree
= (ARENA_FREE
*)pArena
;
460 /* Create a free block */
462 HEAP_CreateFreeBlock( subheap
, pFree
, size
);
463 size
= (pFree
->size
& ARENA_SIZE_MASK
) + sizeof(ARENA_FREE
);
464 if ((char *)pFree
+ size
< (char *)subheap
+ subheap
->size
)
465 return; /* Not the last block, so nothing more to do */
467 /* Free the whole sub-heap if it's empty and not the original one */
469 if (((char *)pFree
== (char *)subheap
+ subheap
->headerSize
) &&
470 (subheap
!= &subheap
->heap
->subheap
))
472 SUBHEAP
*pPrev
= &subheap
->heap
->subheap
;
473 /* Remove the free block from the list */
474 pFree
->next
->prev
= pFree
->prev
;
475 pFree
->prev
->next
= pFree
->next
;
476 /* Remove the subheap from the list */
477 while (pPrev
&& (pPrev
->next
!= subheap
))
480 pPrev
->next
= subheap
->next
;
481 /* Free the memory */
483 ZwFreeVirtualMemory(NtCurrentProcess(),
490 /* Decommit the end of the heap */
494 /***********************************************************************
497 * Shrink an in-use block.
499 static void HEAP_ShrinkBlock(SUBHEAP
*subheap
, ARENA_INUSE
*pArena
, ULONG size
)
501 if ((pArena
->size
& ARENA_SIZE_MASK
) >= size
+ HEAP_MIN_BLOCK_SIZE
)
503 HEAP_CreateFreeBlock( subheap
, (char *)(pArena
+ 1) + size
,
504 (pArena
->size
& ARENA_SIZE_MASK
) - size
);
505 /* assign size plus previous arena flags */
506 pArena
->size
= size
| (pArena
->size
& ~ARENA_SIZE_MASK
);
510 /* Turn off PREV_FREE flag in next block */
511 char *pNext
= (char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
);
512 if (pNext
< (char *)subheap
+ subheap
->size
)
513 *(PULONG
)pNext
&= ~ARENA_FLAG_PREV_FREE
;
517 /***********************************************************************
520 static BOOLEAN
HEAP_InitSubHeap( HEAP
*heap
, PVOID address
, ULONG flags
,
521 SIZE_T commitSize
, ULONG totalSize
,
522 PRTL_HEAP_PARAMETERS Parameters
)
524 SUBHEAP
*subheap
= (SUBHEAP
*)address
;
525 FREE_LIST_ENTRY
*pEntry
;
529 /* Fill the sub-heap structure */
531 subheap
= (PSUBHEAP
)address
;
532 subheap
->heap
= heap
;
533 subheap
->size
= totalSize
;
534 subheap
->commitSize
= commitSize
;
535 subheap
->magic
= SUBHEAP_MAGIC
;
537 if ( subheap
!= (SUBHEAP
*)heap
)
539 /* If this is a secondary subheap, insert it into list */
541 subheap
->headerSize
= sizeof(SUBHEAP
);
542 subheap
->next
= heap
->subheap
.next
;
543 heap
->subheap
.next
= subheap
;
547 /* If this is a primary subheap, initialize main heap */
549 subheap
->headerSize
= sizeof(HEAP
);
550 subheap
->next
= NULL
;
553 heap
->magic
= HEAP_MAGIC
;
555 heap
->commitRoutine
= Parameters
->CommitRoutine
;
557 heap
->commitRoutine
= NULL
;
559 /* Build the free lists */
561 for (i
= 0, pEntry
= heap
->freeList
; i
< HEAP_NB_FREE_LISTS
; i
++, pEntry
++)
563 pEntry
->size
= HEAP_freeListSizes
[i
];
564 pEntry
->arena
.size
= 0 | ARENA_FLAG_FREE
;
565 pEntry
->arena
.next
= i
< HEAP_NB_FREE_LISTS
-1 ?
566 &heap
->freeList
[i
+1].arena
: &heap
->freeList
[0].arena
;
567 pEntry
->arena
.prev
= i
? &heap
->freeList
[i
-1].arena
:
568 &heap
->freeList
[HEAP_NB_FREE_LISTS
-1].arena
;
569 pEntry
->arena
.threadId
= 0;
570 pEntry
->arena
.magic
= ARENA_FREE_MAGIC
;
573 /* Initialize critical section */
575 if (RtlpGetMode() == UserMode
)
577 RtlInitializeHeapLock( &heap
->critSection
);
582 if (heap
->commitRoutine
)
584 if (subheap
!= (SUBHEAP
*)heap
)
586 Status
= heap
->commitRoutine(heap
, &address
, &commitSize
);
590 /* the caller is responsible for committing the first page! */
591 Status
= STATUS_SUCCESS
;
596 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
601 PAGE_EXECUTE_READWRITE
);
603 if (!NT_SUCCESS(Status
))
605 DPRINT("Could not commit %08lx bytes for sub-heap %p\n",
606 commitSize
, address
);
610 /* Create the first free block */
612 HEAP_CreateFreeBlock( subheap
, (PUCHAR
)subheap
+ subheap
->headerSize
,
613 subheap
->size
- subheap
->headerSize
);
618 /***********************************************************************
621 * Create a sub-heap of the given size.
622 * If heap == NULL, creates a main heap.
625 HEAP_CreateSubHeap(PVOID BaseAddress
,
626 HEAP
*heap
, ULONG flags
,
627 SIZE_T commitSize
, ULONG totalSize
,
628 PRTL_HEAP_PARAMETERS Parameters
)
633 /* Round-up sizes on a 64K boundary */
635 totalSize
= (totalSize
+ 0xffff) & 0xffff0000;
636 commitSize
= (commitSize
+ 0xffff) & 0xffff0000;
638 commitSize
= 0x10000;
639 if (totalSize
< commitSize
)
640 totalSize
= commitSize
;
642 /* Allocate the memory block */
643 address
= BaseAddress
;
646 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
650 MEM_RESERVE
| MEM_COMMIT
,
651 PAGE_EXECUTE_READWRITE
);
652 if (!NT_SUCCESS(Status
))
654 DPRINT("Could not VirtualAlloc %08lx bytes\n",
660 /* Initialize subheap */
662 if (!HEAP_InitSubHeap( heap
? heap
: (HEAP
*)address
,
663 address
, flags
, commitSize
, totalSize
,
669 ZwFreeVirtualMemory(NtCurrentProcess(),
677 return (SUBHEAP
*)address
;
681 /***********************************************************************
684 * Find a free block at least as large as the requested size, and make sure
685 * the requested size is committed.
687 static ARENA_FREE
*HEAP_FindFreeBlock( HEAP
*heap
, SIZE_T size
,
688 SUBHEAP
**ppSubHeap
)
692 FREE_LIST_ENTRY
*pEntry
= heap
->freeList
;
694 /* Find a suitable free list, and in it find a block large enough */
696 while (pEntry
->size
< size
)
698 pArena
= pEntry
->arena
.next
;
699 while (pArena
!= &heap
->freeList
[0].arena
)
701 ULONG arena_size
= (pArena
->size
& ARENA_SIZE_MASK
) +
702 sizeof(ARENA_FREE
) - sizeof(ARENA_INUSE
);
703 if (arena_size
>= size
)
705 subheap
= HEAP_FindSubHeap( heap
, pArena
);
706 if (!HEAP_Commit( subheap
, (char *)pArena
+ sizeof(ARENA_INUSE
)
707 + size
+ HEAP_MIN_BLOCK_SIZE
,
710 *ppSubHeap
= subheap
;
714 pArena
= pArena
->next
;
717 /* If no block was found, attempt to grow the heap */
719 if (!(heap
->flags
& HEAP_GROWABLE
))
721 DPRINT("Not enough space in heap %p for %08lx bytes\n",
725 /* make sure that we have a big enough size *committed* to fit another
726 * last free arena in !
727 * So just one heap struct, one first free arena which will eventually
728 * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
729 * might get assigned all remaining free space in HEAP_ShrinkBlock() */
730 size
+= sizeof(SUBHEAP
) + sizeof(ARENA_FREE
) + HEAP_MIN_BLOCK_SIZE
;
731 if (!(subheap
= HEAP_CreateSubHeap( NULL
, heap
, heap
->flags
, size
,
732 max( HEAP_DEF_SIZE
, size
), NULL
)))
735 DPRINT("created new sub-heap %p of %08lx bytes for heap %p\n",
736 subheap
, size
, heap
);
738 *ppSubHeap
= subheap
;
739 return (ARENA_FREE
*)(subheap
+ 1);
743 /***********************************************************************
744 * HEAP_IsValidArenaPtr
746 * Check that the pointer is inside the range possible for arenas.
748 static BOOLEAN
HEAP_IsValidArenaPtr( HEAP
*heap
, PVOID ptr
)
751 SUBHEAP
*subheap
= HEAP_FindSubHeap( heap
, ptr
);
754 if ((char *)ptr
>= (char *)subheap
+ subheap
->headerSize
)
756 if (subheap
!= &heap
->subheap
)
758 for (i
= 0; i
< HEAP_NB_FREE_LISTS
; i
++)
759 if (ptr
== (PVOID
)&heap
->freeList
[i
].arena
)
765 /***********************************************************************
766 * HEAP_ValidateFreeArena
768 static BOOLEAN
HEAP_ValidateFreeArena( SUBHEAP
*subheap
, ARENA_FREE
*pArena
)
770 char *heapEnd
= (char *)subheap
+ subheap
->size
;
772 /* Check magic number */
773 if (pArena
->magic
!= ARENA_FREE_MAGIC
)
775 DPRINT("Heap %p: invalid free arena magic for %p\n",
776 subheap
->heap
, pArena
);
779 /* Check size flags */
780 if (!(pArena
->size
& ARENA_FLAG_FREE
) ||
781 (pArena
->size
& ARENA_FLAG_PREV_FREE
))
783 DPRINT("Heap %p: bad flags %lx for free arena %p\n",
784 subheap
->heap
, pArena
->size
& ~ARENA_SIZE_MASK
, pArena
);
786 /* Check arena size */
787 if ((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) > heapEnd
)
789 DPRINT("Heap %p: bad size %08lx for free arena %p\n",
790 subheap
->heap
, (ULONG
)pArena
->size
& ARENA_SIZE_MASK
, pArena
);
793 /* Check that next pointer is valid */
794 if (!HEAP_IsValidArenaPtr( subheap
->heap
, pArena
->next
))
796 DPRINT("Heap %p: bad next ptr %p for arena %p\n",
797 subheap
->heap
, pArena
->next
, pArena
);
800 /* Check that next arena is free */
801 if (!(pArena
->next
->size
& ARENA_FLAG_FREE
) ||
802 (pArena
->next
->magic
!= ARENA_FREE_MAGIC
))
804 DPRINT("Heap %p: next arena %p invalid for %p\n",
805 subheap
->heap
, pArena
->next
, pArena
);
808 /* Check that prev pointer is valid */
809 if (!HEAP_IsValidArenaPtr( subheap
->heap
, pArena
->prev
))
811 DPRINT("Heap %p: bad prev ptr %p for arena %p\n",
812 subheap
->heap
, pArena
->prev
, pArena
);
815 /* Check that prev arena is free */
816 if (!(pArena
->prev
->size
& ARENA_FLAG_FREE
) ||
817 (pArena
->prev
->magic
!= ARENA_FREE_MAGIC
))
819 DPRINT("Heap %p: prev arena %p invalid for %p\n",
820 subheap
->heap
, pArena
->prev
, pArena
);
823 /* Check that next block has PREV_FREE flag */
824 if ((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) < heapEnd
)
826 if (!(*(PULONG
)((char *)(pArena
+ 1) +
827 (pArena
->size
& ARENA_SIZE_MASK
)) & ARENA_FLAG_PREV_FREE
))
829 DPRINT("Heap %p: free arena %p next block has no PREV_FREE flag\n",
830 subheap
->heap
, pArena
);
833 /* Check next block back pointer */
834 if (*((ARENA_FREE
**)((char *)(pArena
+ 1) +
835 (pArena
->size
& ARENA_SIZE_MASK
)) - 1) != pArena
)
837 DPRINT("Heap %p: arena %p has wrong back ptr %lx\n",
838 subheap
->heap
, pArena
,
839 *((PULONG
)((char *)(pArena
+1)+ (pArena
->size
& ARENA_SIZE_MASK
)) - 1));
847 /***********************************************************************
848 * HEAP_ValidateInUseArena
850 static BOOLEAN
HEAP_ValidateInUseArena( SUBHEAP
*subheap
, ARENA_INUSE
*pArena
, BOOLEAN quiet
)
852 char *heapEnd
= (char *)subheap
+ subheap
->size
;
854 /* Check magic number */
855 if (pArena
->magic
!= ARENA_INUSE_MAGIC
)
859 DPRINT("Heap %p: invalid in-use arena magic for %p\n",
860 subheap
->heap
, pArena
);
862 HEAP_Dump( subheap
->heap
);
864 else if (WARN_ON(heap
))
866 DPRINT("Heap %p: invalid in-use arena magic for %p\n",
867 subheap
->heap
, pArena
);
869 HEAP_Dump( subheap
->heap
);
873 /* Check size flags */
874 if (pArena
->size
& ARENA_FLAG_FREE
)
876 DPRINT("Heap %p: bad flags %lx for in-use arena %p\n",
877 subheap
->heap
, pArena
->size
& ~ARENA_SIZE_MASK
, pArena
);
880 /* Check arena size */
881 if ((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) > heapEnd
)
883 DPRINT("Heap %p: bad size %08lx for in-use arena %p\n",
884 subheap
->heap
, (ULONG
)pArena
->size
& ARENA_SIZE_MASK
, pArena
);
887 /* Check next arena PREV_FREE flag */
888 if (((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
) < heapEnd
) &&
889 (*(PULONG
)((char *)(pArena
+ 1) + (pArena
->size
& ARENA_SIZE_MASK
)) & ARENA_FLAG_PREV_FREE
))
891 DPRINT("Heap %p: in-use arena %p next block has PREV_FREE flag\n",
892 subheap
->heap
, pArena
);
895 /* Check prev free arena */
896 if (pArena
->size
& ARENA_FLAG_PREV_FREE
)
898 ARENA_FREE
*pPrev
= *((ARENA_FREE
**)pArena
- 1);
899 /* Check prev pointer */
900 if (!HEAP_IsValidArenaPtr( subheap
->heap
, pPrev
))
902 DPRINT("Heap %p: bad back ptr %p for arena %p\n",
903 subheap
->heap
, pPrev
, pArena
);
906 /* Check that prev arena is free */
907 if (!(pPrev
->size
& ARENA_FLAG_FREE
) ||
908 (pPrev
->magic
!= ARENA_FREE_MAGIC
))
910 DPRINT("Heap %p: prev arena %p invalid for in-use %p\n",
911 subheap
->heap
, pPrev
, pArena
);
914 /* Check that prev arena is really the previous block */
915 if ((char *)(pPrev
+ 1) + (pPrev
->size
& ARENA_SIZE_MASK
) != (char *)pArena
)
917 DPRINT("Heap %p: prev arena %p is not prev for in-use %p\n",
918 subheap
->heap
, pPrev
, pArena
);
926 /***********************************************************************
928 * Checks whether the pointer points to a block inside a given heap.
931 * Should this return BOOL32?
937 int HEAP_IsInsideHeap(
938 HANDLE heap
, /* [in] Heap */
939 ULONG flags
, /* [in] Flags */
940 PVOID ptr
/* [in] Pointer */
943 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
947 /* Validate the parameters */
951 flags
|= heapPtr
->flags
;
952 if (!(flags
& HEAP_NO_SERIALIZE
))
953 RtlEnterHeapLock( &heapPtr
->critSection
);
954 ret
= (((subheap
= HEAP_FindSubHeap( heapPtr
, ptr
)) != NULL
) &&
955 (((char *)ptr
>= (char *)subheap
+ subheap
->headerSize
956 + sizeof(ARENA_INUSE
))));
957 if (!(flags
& HEAP_NO_SERIALIZE
))
958 RtlLeaveHeapLock( &heapPtr
->critSection
);
963 void DumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
967 DbgPrint("Frames: ");
971 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
972 #elif defined(_MSC_VER)
973 __asm mov
[Frame
], ebp
975 Frame
= (PULONG
)Frame
[0]; // step out of DumpStackFrames
977 while ( Frame
!= 0 && (ULONG
)Frame
!= 0xDEADBEEF && (ULONG
)Frame
!= 0xcdcdcdcd && (ULONG
)Frame
!= 0xcccccccc && i
++ < FrameCount
)
979 DbgPrint("<%p>", (PVOID
)Frame
[1]);
980 if (Frame
[1] == 0xdeadbeef)
982 Frame
= (PULONG
)Frame
[0];
988 /***********************************************************************
989 * HEAP_IsRealArena [Internal]
990 * Validates a block is a valid arena.
996 static BOOLEAN
HEAP_IsRealArena(
997 HANDLE heap
, /* [in] Handle to the heap */
998 ULONG flags
, /* [in] Bit flags that control access during operation */
999 PVOID block
, /* [in] Optional pointer to memory block to validate */
1000 BOOLEAN quiet
/* [in] Flag - if true, HEAP_ValidateInUseArena
1001 * does not complain */
1005 HEAP
*heapPtr
= (HEAP
*)(heap
);
1008 if (!heapPtr
|| (heapPtr
->magic
!= HEAP_MAGIC
))
1010 DPRINT("Invalid heap %p!\n", heap
);
1014 flags
&= HEAP_NO_SERIALIZE
;
1015 flags
|= heapPtr
->flags
;
1016 /* calling HeapLock may result in infinite recursion, so do the critsect directly */
1017 if (!(flags
& HEAP_NO_SERIALIZE
))
1018 RtlEnterHeapLock( &heapPtr
->critSection
);
1022 /* Only check this single memory block */
1024 /* The following code is really HEAP_IsInsideHeap *
1025 * with serialization already done. */
1026 if (!(subheap
= HEAP_FindSubHeap( heapPtr
, block
)) ||
1027 ((char *)block
< (char *)subheap
+ subheap
->headerSize
1028 + sizeof(ARENA_INUSE
)))
1032 DPRINT("Heap %p: block %p is not inside heap\n",
1034 DumpStackFrames(NULL
,10);
1036 else if (WARN_ON(heap
))
1038 DPRINT1("Heap %p: block %p is not inside heap\n",
1040 DumpStackFrames(NULL
,10);
1045 ret
= HEAP_ValidateInUseArena( subheap
, (ARENA_INUSE
*)block
- 1, quiet
);
1047 if (!(flags
& HEAP_NO_SERIALIZE
))
1048 RtlLeaveHeapLock( &heapPtr
->critSection
);
1052 subheap
= &heapPtr
->subheap
;
1053 while (subheap
&& ret
)
1055 char *ptr
= (char *)subheap
+ subheap
->headerSize
;
1056 while (ptr
< (char *)subheap
+ subheap
->size
)
1058 if (*(PULONG
)ptr
& ARENA_FLAG_FREE
)
1060 if (!HEAP_ValidateFreeArena( subheap
, (ARENA_FREE
*)ptr
))
1065 ptr
+= sizeof(ARENA_FREE
) + (*(PULONG
)ptr
& ARENA_SIZE_MASK
);
1069 if (!HEAP_ValidateInUseArena( subheap
, (ARENA_INUSE
*)ptr
, NOISY
))
1074 ptr
+= sizeof(ARENA_INUSE
) + (*(PULONG
)ptr
& ARENA_SIZE_MASK
);
1077 subheap
= subheap
->next
;
1080 if (!(flags
& HEAP_NO_SERIALIZE
))
1081 RtlLeaveHeapLock( &heapPtr
->critSection
);
1086 /***********************************************************************
1087 * HeapCreate (KERNEL32.336)
1089 * Handle of heap: Success
1095 RtlCreateHeap(ULONG flags
,
1100 PRTL_HEAP_PARAMETERS Parameters
)
1105 /* Allocate the heap block */
1109 maxSize
= HEAP_DEF_SIZE
;
1110 flags
|= HEAP_GROWABLE
;
1112 if (!(subheap
= HEAP_CreateSubHeap( BaseAddress
, NULL
, flags
, initialSize
,
1113 maxSize
, Parameters
)))
1118 if (RtlpGetMode() == UserMode
)
1120 /* link it into the per-process heap list */
1121 RtlEnterHeapLock (&RtlpProcessHeapsListLock
);
1123 heapPtr
= subheap
->heap
;
1124 heapPtr
->next
= (HEAP
*)NtCurrentPeb()->ProcessHeaps
;
1125 NtCurrentPeb()->ProcessHeaps
= (HANDLE
)heapPtr
;
1126 NtCurrentPeb()->NumberOfHeaps
++;
1128 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1131 return (HANDLE
)subheap
;
1134 /***********************************************************************
1135 * HeapDestroy (KERNEL32.337)
1143 * Success: A NULL HANDLE, if heap is NULL or it was destroyed
1144 * Failure: The Heap handle, if heap is the process heap.
1147 RtlDestroyHeap(HANDLE heap
) /* [in] Handle of heap */
1149 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
1154 DPRINT("%p\n", heap
);
1158 if (RtlpGetMode() == UserMode
)
1160 if (heap
== NtCurrentPeb()->ProcessHeap
)
1161 return heap
; /* cannot delete the main process heap */
1163 /* remove it from the per-process list */
1164 RtlEnterHeapLock (&RtlpProcessHeapsListLock
);
1166 pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
;
1167 while (*pptr
&& *pptr
!= heapPtr
) pptr
= &(*pptr
)->next
;
1168 if (*pptr
) *pptr
= (*pptr
)->next
;
1169 NtCurrentPeb()->NumberOfHeaps
--;
1171 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1174 RtlDeleteHeapLock( &heapPtr
->critSection
);
1175 subheap
= &heapPtr
->subheap
;
1176 // We must save the flags. The first subheap is located after
1177 // the heap structure. If we release the first subheap,
1178 // we release also the heap structure.
1179 flags
= heapPtr
->flags
;
1182 SUBHEAP
*next
= subheap
->next
;
1183 ULONG dummySize
= 0;
1184 ZwFreeVirtualMemory(NtCurrentProcess(),
1190 return (HANDLE
)NULL
;
1194 /***********************************************************************
1195 * HeapAlloc (KERNEL32.334)
1197 * Pointer to allocated memory block
1199 * 0x7d030f60--invalid flags in RtlHeapAllocate
1203 RtlAllocateHeap(HANDLE heap
, /* [in] Handle of private heap block */
1204 ULONG flags
, /* [in] Heap allocation control flags */
1205 ULONG size
) /* [in] Number of bytes to allocate */
1208 ARENA_INUSE
*pInUse
;
1210 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
1212 /* Validate the parameters */
1216 if (flags
& HEAP_GENERATE_EXCEPTIONS
)
1217 RtlRaiseStatus( STATUS_NO_MEMORY
);
1220 //flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
1221 flags
|= heapPtr
->flags
;
1222 if (!(flags
& HEAP_NO_SERIALIZE
))
1223 RtlEnterHeapLock( &heapPtr
->critSection
);
1224 size
= (size
+ 7) & ~7;
1225 if (size
< HEAP_MIN_BLOCK_SIZE
)
1226 size
= HEAP_MIN_BLOCK_SIZE
;
1228 /* Locate a suitable free block */
1230 if (!(pArena
= HEAP_FindFreeBlock( heapPtr
, size
, &subheap
)))
1232 DPRINT("(%p,%08lx,%08lx): returning NULL\n",
1233 heap
, flags
, size
);
1234 if (!(flags
& HEAP_NO_SERIALIZE
))
1235 RtlLeaveHeapLock( &heapPtr
->critSection
);
1236 if (flags
& HEAP_GENERATE_EXCEPTIONS
)
1237 RtlRaiseStatus( STATUS_NO_MEMORY
);
1241 /* Remove the arena from the free list */
1243 pArena
->next
->prev
= pArena
->prev
;
1244 pArena
->prev
->next
= pArena
->next
;
1246 /* Build the in-use arena */
1248 pInUse
= (ARENA_INUSE
*)pArena
;
1249 pInUse
->size
= (pInUse
->size
& ~ARENA_FLAG_FREE
)
1250 + sizeof(ARENA_FREE
) - sizeof(ARENA_INUSE
);
1251 pInUse
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
1252 pInUse
->magic
= ARENA_INUSE_MAGIC
;
1254 /* Save user flags */
1255 subheap
->UserFlags
= flags
& HEAP_SETTABLE_USER_FLAGS
;
1257 /* Shrink the block */
1259 HEAP_ShrinkBlock( subheap
, pInUse
, size
);
1261 if (flags
& HEAP_ZERO_MEMORY
)
1262 memset( pInUse
+ 1, 0, pInUse
->size
& ARENA_SIZE_MASK
);
1263 else if (TRACE_ON(heap
))
1264 memset( pInUse
+ 1, ARENA_INUSE_FILLER
, pInUse
->size
& ARENA_SIZE_MASK
);
1266 if (!(flags
& HEAP_NO_SERIALIZE
))
1267 RtlLeaveHeapLock( &heapPtr
->critSection
);
1269 DPRINT("(%p,%08lx,%08lx): returning %p\n",
1270 heap
, flags
, size
, (PVOID
)(pInUse
+ 1) );
1271 return (PVOID
)(pInUse
+ 1);
1275 /***********************************************************************
1276 * HeapFree (KERNEL32.338)
1283 BOOLEAN NTAPI
RtlFreeHeap(
1284 HANDLE heap
, /* [in] Handle of heap */
1285 ULONG flags
, /* [in] Heap freeing flags */
1286 PVOID ptr
/* [in] Address of memory to free */
1289 ARENA_INUSE
*pInUse
;
1291 HEAP
*heapPtr
= HEAP_GetPtr( heap
);
1293 /* Validate the parameters */
1297 if (!ptr
) /* Freeing a NULL ptr is doesn't indicate an error in Win2k */
1299 DPRINT("(%p,%08lx,%p): asked to free NULL\n",
1304 flags
&= HEAP_NO_SERIALIZE
;
1305 flags
|= heapPtr
->flags
;
1306 if (!(flags
& HEAP_NO_SERIALIZE
))
1307 RtlEnterHeapLock( &heapPtr
->critSection
);
1308 if (!HEAP_IsRealArena( heap
, HEAP_NO_SERIALIZE
, ptr
, QUIET
))
1310 if (!(flags
& HEAP_NO_SERIALIZE
))
1311 RtlLeaveHeapLock( &heapPtr
->critSection
);
1312 DPRINT("(%p,%08lx,%p): returning FALSE\n",
1317 /* Turn the block into a free block */
1319 pInUse
= (ARENA_INUSE
*)ptr
- 1;
1320 subheap
= HEAP_FindSubHeap( heapPtr
, pInUse
);
1321 HEAP_MakeInUseBlockFree( subheap
, pInUse
, heapPtr
->flags
);
1323 if (!(flags
& HEAP_NO_SERIALIZE
))
1324 RtlLeaveHeapLock( &heapPtr
->critSection
);
1326 DPRINT("(%p,%08lx,%p): returning TRUE\n",
1332 /***********************************************************************
1335 * Heap [in] Handle of heap block
1336 * Flags [in] Heap reallocation flags
1337 * Ptr, [in] Address of memory to reallocate
1338 * Size [in] Number of bytes to reallocate
1341 * Pointer to reallocated memory block
1343 * 0x7d030f60--invalid flags in RtlHeapAllocate
1346 PVOID NTAPI
RtlReAllocateHeap(
1353 ARENA_INUSE
*pArena
;
1360 if (!(heapPtr
= HEAP_GetPtr( Heap
)))
1363 /* Validate the parameters */
1365 //Flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
1366 // HEAP_REALLOC_IN_PLACE_ONLY;
1367 Flags
|= heapPtr
->flags
;
1368 Size
= (Size
+ 7) & ~7;
1369 if (Size
< HEAP_MIN_BLOCK_SIZE
)
1370 Size
= HEAP_MIN_BLOCK_SIZE
;
1372 if (!(Flags
& HEAP_NO_SERIALIZE
))
1373 RtlEnterHeapLock( &heapPtr
->critSection
);
1374 if (!HEAP_IsRealArena( Heap
, HEAP_NO_SERIALIZE
, Ptr
, QUIET
))
1376 if (!(Flags
& HEAP_NO_SERIALIZE
))
1377 RtlLeaveHeapLock( &heapPtr
->critSection
);
1378 DPRINT("(%p,%08lx,%p,%08lx): returning NULL\n",
1379 Heap
, Flags
, Ptr
, Size
);
1380 if (Flags
& HEAP_GENERATE_EXCEPTIONS
)
1381 RtlRaiseStatus( STATUS_NO_MEMORY
);
1385 /* Check if we need to grow the block */
1387 pArena
= (ARENA_INUSE
*)Ptr
- 1;
1388 pArena
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
1390 subheap
= HEAP_FindSubHeap( heapPtr
, pArena
);
1391 oldSize
= (pArena
->size
& ARENA_SIZE_MASK
);
1394 char *pNext
= (char *)(pArena
+ 1) + oldSize
;
1395 if ((pNext
< (char *)subheap
+ subheap
->size
) &&
1396 (*(PULONG
)pNext
& ARENA_FLAG_FREE
) &&
1397 (oldSize
+ (*(PULONG
)pNext
& ARENA_SIZE_MASK
) + sizeof(ARENA_FREE
) >= Size
))
1399 /* The next block is free and large enough */
1400 ARENA_FREE
*pFree
= (ARENA_FREE
*)pNext
;
1401 pFree
->next
->prev
= pFree
->prev
;
1402 pFree
->prev
->next
= pFree
->next
;
1403 pArena
->size
+= (pFree
->size
& ARENA_SIZE_MASK
) + sizeof(*pFree
);
1404 if (!HEAP_Commit( subheap
, (char *)pArena
+ sizeof(ARENA_INUSE
)
1405 + Size
+ HEAP_MIN_BLOCK_SIZE
,
1408 if (!(Flags
& HEAP_NO_SERIALIZE
))
1409 RtlLeaveHeapLock( &heapPtr
->critSection
);
1410 if (Flags
& HEAP_GENERATE_EXCEPTIONS
)
1411 RtlRaiseStatus( STATUS_NO_MEMORY
);
1414 HEAP_ShrinkBlock( subheap
, pArena
, Size
);
1416 else /* Do it the hard way */
1419 ARENA_INUSE
*pInUse
;
1420 SUBHEAP
*newsubheap
;
1422 if ((Flags
& HEAP_REALLOC_IN_PLACE_ONLY
) ||
1423 !(pNew
= HEAP_FindFreeBlock( heapPtr
, Size
, &newsubheap
)))
1425 if (!(Flags
& HEAP_NO_SERIALIZE
))
1426 RtlLeaveHeapLock( &heapPtr
->critSection
);
1427 if (Flags
& HEAP_GENERATE_EXCEPTIONS
)
1428 RtlRaiseStatus( STATUS_NO_MEMORY
);
1432 /* Build the in-use arena */
1434 pNew
->next
->prev
= pNew
->prev
;
1435 pNew
->prev
->next
= pNew
->next
;
1436 pInUse
= (ARENA_INUSE
*)pNew
;
1437 pInUse
->size
= (pInUse
->size
& ~ARENA_FLAG_FREE
)
1438 + sizeof(ARENA_FREE
) - sizeof(ARENA_INUSE
);
1439 pInUse
->threadId
= (ULONG
)NtCurrentTeb()->Cid
.UniqueThread
;
1440 pInUse
->magic
= ARENA_INUSE_MAGIC
;
1441 HEAP_ShrinkBlock( newsubheap
, pInUse
, Size
);
1442 memcpy( pInUse
+ 1, pArena
+ 1, oldSize
);
1444 /* Free the previous block */
1446 HEAP_MakeInUseBlockFree( subheap
, pArena
, Flags
);
1447 subheap
= newsubheap
;
1452 HEAP_ShrinkBlock( subheap
, pArena
, Size
); /* Shrink the block */
1454 /* Clear the extra bytes if needed */
1458 if (Flags
& HEAP_ZERO_MEMORY
)
1459 memset( (char *)(pArena
+ 1) + oldSize
, 0,
1460 (pArena
->size
& ARENA_SIZE_MASK
) - oldSize
);
1461 else if (TRACE_ON(heap
))
1462 memset( (char *)(pArena
+ 1) + oldSize
, ARENA_INUSE_FILLER
,
1463 (pArena
->size
& ARENA_SIZE_MASK
) - oldSize
);
1466 /* Return the new arena */
1468 if (!(Flags
& HEAP_NO_SERIALIZE
))
1469 RtlLeaveHeapLock( &heapPtr
->critSection
);
1471 DPRINT("(%p,%08lx,%p,%08lx): returning %p\n",
1472 Heap
, Flags
, Ptr
, Size
, (PVOID
)(pArena
+ 1) );
1473 return (PVOID
)(pArena
+ 1);
1477 /***********************************************************************
1483 RtlCompactHeap(HANDLE Heap
,
1491 /***********************************************************************
1493 * Attempts to acquire the critical section object for a specified heap.
1496 * Heap [in] Handle of heap to lock for exclusive access
1505 RtlLockHeap(IN HANDLE Heap
)
1507 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1510 RtlEnterHeapLock( &heapPtr
->critSection
);
1515 /***********************************************************************
1517 * Releases ownership of the critical section object.
1520 * Heap [in] Handle to the heap to unlock
1529 RtlUnlockHeap(HANDLE Heap
)
1531 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1534 RtlLeaveHeapLock( &heapPtr
->critSection
);
1539 /***********************************************************************
1542 * Heap [in] Handle of heap
1543 * Flags [in] Heap size control flags
1544 * Ptr [in] Address of memory to return size for
1547 * Size in bytes of allocated memory
1548 * 0xffffffff: Failure
1560 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1564 Flags
&= HEAP_NO_SERIALIZE
;
1565 Flags
|= heapPtr
->flags
;
1566 if (!(Flags
& HEAP_NO_SERIALIZE
))
1567 RtlEnterHeapLock( &heapPtr
->critSection
);
1568 if (!HEAP_IsRealArena( Heap
, HEAP_NO_SERIALIZE
, Ptr
, QUIET
))
1574 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)Ptr
- 1;
1575 ret
= pArena
->size
& ARENA_SIZE_MASK
;
1577 if (!(Flags
& HEAP_NO_SERIALIZE
))
1578 RtlLeaveHeapLock( &heapPtr
->critSection
);
1580 DPRINT("(%p,%08lx,%p): returning %08lx\n",
1581 Heap
, Flags
, Ptr
, ret
);
1586 /***********************************************************************
1588 * Validates a specified heap.
1591 * Heap [in] Handle to the heap
1592 * Flags [in] Bit flags that control access during operation
1593 * Block [in] Optional pointer to memory block to validate
1604 BOOLEAN NTAPI
RtlValidateHeap(
1610 HEAP
*heapPtr
= HEAP_GetPtr( Heap
);
1613 return HEAP_IsRealArena( heapPtr
, Flags
, Block
, QUIET
);
1617 /***********************************************************************
1618 * HeapWalk (KERNEL32.344)
1619 * Enumerates the memory blocks in a specified heap.
1620 * See HEAP_Dump() for info on heap structure.
1623 * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
1624 * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
1631 BOOLEAN NTAPI
HeapWalk(
1632 HANDLE heap
, /* [in] Handle to heap to enumerate */
1633 LPPROCESS_HEAP_ENTRY entry
/* [out] Pointer to structure of enumeration info */
1636 HEAP
*heapPtr
= HEAP_GetPtr(heap
);
1637 SUBHEAP
*sub
, *currentheap
= NULL
;
1638 BOOLEAN ret
= FALSE
;
1640 int region_index
= 0;
1642 if (!heapPtr
|| !entry
)
1647 if (!(heapPtr
->flags
& HEAP_NO_SERIALIZE
))
1648 RtlEnterHeapLock( &heapPtr
->critSection
);
1650 /* set ptr to the next arena to be examined */
1652 if (!entry
->lpData
) /* first call (init) ? */
1654 DPRINT("begin walking of heap 0x%08x.\n", heap
);
1655 /*HEAP_Dump(heapPtr);*/
1656 currentheap
= &heapPtr
->subheap
;
1657 ptr
= (char*)currentheap
+ currentheap
->headerSize
;
1661 ptr
= entry
->lpData
;
1662 sub
= &heapPtr
->subheap
;
1665 if (((char *)ptr
>= (char *)sub
) &&
1666 ((char *)ptr
< (char *)sub
+ sub
->size
))
1674 if (currentheap
== NULL
)
1676 DPRINT("no matching subheap found, shouldn't happen !\n");
1680 ptr
+= entry
->cbData
; /* point to next arena */
1681 if (ptr
> (char *)currentheap
+ currentheap
->size
- 1)
1682 { /* proceed with next subheap */
1683 if (!(currentheap
= currentheap
->next
))
1684 { /* successfully finished */
1685 DPRINT("end reached.\n");
1688 ptr
= (char*)currentheap
+ currentheap
->headerSize
;
1693 if (*(PULONG
)ptr
& ARENA_FLAG_FREE
)
1695 ARENA_FREE
*pArena
= (ARENA_FREE
*)ptr
;
1697 /*DPRINT("free, magic: %04x\n", pArena->magic);*/
1699 entry
->lpData
= pArena
+ 1;
1700 entry
->cbData
= pArena
->size
& ARENA_SIZE_MASK
;
1701 entry
->cbOverhead
= sizeof(ARENA_FREE
);
1702 entry
->wFlags
= PROCESS_HEAP_UNCOMMITTED_RANGE
;
1706 ARENA_INUSE
*pArena
= (ARENA_INUSE
*)ptr
;
1708 /*DPRINT("busy, magic: %04x\n", pArena->magic);*/
1710 entry
->lpData
= pArena
+ 1;
1711 entry
->cbData
= pArena
->size
& ARENA_SIZE_MASK
;
1712 entry
->cbOverhead
= sizeof(ARENA_INUSE
);
1713 entry
->wFlags
= PROCESS_HEAP_ENTRY_BUSY
;
1714 /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
1715 and PROCESS_HEAP_ENTRY_DDESHARE yet */
1718 entry
->iRegionIndex
= region_index
;
1720 /* first element of heap ? */
1721 if (ptr
== (char *)(currentheap
+ currentheap
->headerSize
))
1723 entry
->wFlags
|= PROCESS_HEAP_REGION
;
1724 entry
->Foo
.Region
.dwCommittedSize
= currentheap
->commitSize
;
1725 entry
->Foo
.Region
.dwUnCommittedSize
=
1726 currentheap
->size
- currentheap
->commitSize
;
1727 entry
->Foo
.Region
.lpFirstBlock
= /* first valid block */
1728 currentheap
+ currentheap
->headerSize
;
1729 entry
->Foo
.Region
.lpLastBlock
= /* first invalid block */
1730 currentheap
+ currentheap
->size
;
1735 if (!(heapPtr
->flags
& HEAP_NO_SERIALIZE
))
1736 RtlLeaveHeapLock( &heapPtr
->critSection
);
1744 RtlInitializeHeapManager(VOID
)
1748 Peb
= NtCurrentPeb();
1750 Peb
->NumberOfHeaps
= 0;
1751 Peb
->MaximumNumberOfHeaps
= -1; /* no limit */
1752 Peb
->ProcessHeaps
= NULL
;
1754 RtlInitializeHeapLock(&RtlpProcessHeapsListLock
);
1762 RtlEnumProcessHeaps(PHEAP_ENUMERATION_ROUTINE HeapEnumerationRoutine
,
1765 NTSTATUS Status
= STATUS_SUCCESS
;
1768 RtlEnterHeapLock(&RtlpProcessHeapsListLock
);
1770 for (pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
; *pptr
; pptr
= &(*pptr
)->next
)
1772 Status
= HeapEnumerationRoutine(*pptr
,lParam
);
1773 if (!NT_SUCCESS(Status
))
1777 RtlLeaveHeapLock(&RtlpProcessHeapsListLock
);
1787 RtlGetProcessHeaps(ULONG HeapCount
,
1793 RtlEnterHeapLock(&RtlpProcessHeapsListLock
);
1795 Result
= NtCurrentPeb()->NumberOfHeaps
;
1797 if (NtCurrentPeb()->NumberOfHeaps
<= HeapCount
)
1800 for (pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
; *pptr
; pptr
= &(*pptr
)->next
)
1802 HeapArray
[i
++] = *pptr
;
1806 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1816 RtlValidateProcessHeaps(VOID
)
1818 BOOLEAN Result
= TRUE
;
1821 RtlEnterHeapLock(&RtlpProcessHeapsListLock
);
1823 for (pptr
= (HEAP
**)&NtCurrentPeb()->ProcessHeaps
; *pptr
; pptr
= &(*pptr
)->next
)
1825 if (!RtlValidateHeap(*pptr
, 0, NULL
))
1832 RtlLeaveHeapLock (&RtlpProcessHeapsListLock
);
1843 IN PVOID HeapHandle
,
1856 RtlSetUserValueHeap(IN PVOID HeapHandle
,
1858 IN PVOID BaseAddress
,
1861 HEAP
*heapPtr
= HEAP_GetPtr(HeapHandle
);
1862 ARENA_INUSE
*pInUse
;
1865 /* Get the subheap */
1866 pInUse
= (ARENA_INUSE
*)BaseAddress
- 1;
1867 subheap
= HEAP_FindSubHeap( heapPtr
, pInUse
);
1870 subheap
->UserValue
= UserValue
;
1879 RtlGetUserInfoHeap(IN PVOID HeapHandle
,
1881 IN PVOID BaseAddress
,
1882 OUT PVOID
*UserValue
,
1883 OUT PULONG UserFlags
)
1885 HEAP
*heapPtr
= HEAP_GetPtr(HeapHandle
);
1886 ARENA_INUSE
*pInUse
;
1889 /* Get the subheap */
1890 pInUse
= (ARENA_INUSE
*)BaseAddress
- 1;
1891 subheap
= HEAP_FindSubHeap( heapPtr
, pInUse
);
1894 DPRINT1("V/F: %lx %p\n", subheap
->UserValue
, subheap
->UserFlags
);
1895 if (UserValue
) *UserValue
= subheap
->UserValue
;
1896 if (UserFlags
) *UserFlags
= subheap
->UserFlags
;
1905 RtlUsageHeap(IN HANDLE Heap
,
1907 OUT PRTL_HEAP_USAGE Usage
)
1911 return STATUS_NOT_IMPLEMENTED
;
1916 RtlQueryTagHeap(IN PVOID HeapHandle
,
1919 IN BOOLEAN ResetCounters
,
1920 OUT PRTL_HEAP_TAG_INFO HeapTagInfo
)
1929 RtlExtendHeap(IN HANDLE Heap
,
1941 RtlCreateTagHeap(IN HANDLE HeapHandle
,
1944 IN PWSTR TagSubName
)