From: Rémi Bernon rbernon@codeweavers.com
And use them to cleanup HEAP_Dump, renaming it to heap_dump.
They will be used to cleanup and simplify the heap implementation. They will make changing the block and subheap layouts easier later.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 216 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 150 insertions(+), 66 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 51567d0552b..424f060b719 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -39,19 +39,21 @@
WINE_DEFAULT_DEBUG_CHANNEL(heap);
-/* Note: the heap data structures are loosely based on what Pietrek describes in his - * book 'Windows 95 System Programming Secrets', with some adaptations for - * better compatibility with NT. - */ +/* header for heap blocks */
-typedef struct tagARENA_INUSE +typedef struct block { DWORD size; /* Block size; must be the first field */ DWORD magic : 24; /* Magic number */ DWORD unused_bytes : 8; /* Number of bytes in the block not used by user data (max value is HEAP_MIN_DATA_SIZE+HEAP_MIN_SHRINK_SIZE) */ } ARENA_INUSE;
-typedef struct tagARENA_FREE +C_ASSERT( sizeof(struct block) == 8 ); + + +/* entry to link free blocks in free lists */ + +typedef struct entry { DWORD size; /* Block size; must be the first field */ DWORD magic; /* Magic number */ @@ -181,6 +183,73 @@ typedef struct tagHEAP
static HEAP *processHeap; /* main process heap */
+/* check if memory range a contains memory range b */ +static inline BOOL contains( const void *a, SIZE_T a_size, const void *b, SIZE_T b_size ) +{ + const void *a_end = (char *)a + a_size, *b_end = (char *)b + b_size; + return a <= b && b <= b_end && b_end <= a_end; +} + +static inline UINT block_get_flags( const struct block *block ) +{ + return block->size & ~ARENA_SIZE_MASK; +} + +static inline UINT block_get_type( const struct block *block ) +{ + if (block_get_flags( block ) & ARENA_FLAG_FREE) return (block->unused_bytes << 24)|block->magic; + return block->magic; +} + +static inline UINT block_get_overhead( const struct block *block ) +{ + if (block_get_flags( block ) & ARENA_FLAG_FREE) return sizeof(struct entry); + return sizeof(*block) + block->unused_bytes; +} + +/* return the size of a block, including its header */ +static inline UINT block_get_size( const struct block *block ) +{ + UINT data_size = block->size & ARENA_SIZE_MASK, size = data_size; + if (block_get_flags( block ) & ARENA_FLAG_FREE) size += sizeof(struct entry); + else size += sizeof(*block); + if (size < data_size) return ~0u; + return size; +} + +static inline void *subheap_base( const SUBHEAP *subheap ) +{ + return subheap->base; +} + +static inline SIZE_T subheap_size( const SUBHEAP *subheap ) +{ + return subheap->size; +} + +static inline const void *subheap_commit_end( const SUBHEAP *subheap ) +{ + return (char *)subheap_base( subheap ) + subheap->commitSize; +} + +static inline void *first_block( const SUBHEAP *subheap ) +{ + return (char *)subheap_base( subheap ) + subheap->headerSize; +} + +static inline const void *last_block( const SUBHEAP *subheap ) +{ + return (char *)subheap_commit_end( subheap ) - sizeof(struct block); +} + +static inline struct block *next_block( const SUBHEAP *subheap, const struct block *block ) +{ + const char *data = (char *)(block + 1), *next, *last = last_block( subheap ); + next = (char *)block + block_get_size( block ); + if (!contains( data, last - (char *)data, next, sizeof(*block) )) return NULL; + return (struct block *)next; +} + static BOOL heap_validate( HEAP *heap, BOOL quiet );
/* mark a block of memory as free for debugging purposes */ @@ -355,72 +424,87 @@ static void heap_set_status( const HEAP *heap, ULONG flags, NTSTATUS status ) if (status) RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status ); }
-/*********************************************************************** - * HEAP_Dump - */ -static void HEAP_Dump( HEAP *heap ) +static void heap_dump( const HEAP *heap ) { + const struct block *block; + const ARENA_LARGE *large; + const SUBHEAP *subheap; unsigned int i; - SUBHEAP *subheap; - char *ptr; + SIZE_T size;
- TRACE( "Heap: %p\n", heap ); - TRACE( "Next: %p Sub-heaps:", LIST_ENTRY( heap->entry.next, HEAP, entry ) ); - LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) TRACE( " %p", subheap ); + TRACE( "heap: %p\n", heap ); + TRACE( " next %p\n", LIST_ENTRY( heap->entry.next, HEAP, entry ) );
- TRACE( "\nFree lists:\n Block Stat Size Id\n" ); + TRACE( " free_lists: %p\n", heap->freeList ); for (i = 0; i < HEAP_NB_FREE_LISTS; i++) - TRACE( "%p free %08lx prev=%p next=%p\n", - &heap->freeList[i].arena, i < HEAP_NB_SMALL_FREE_LISTS ? - HEAP_MIN_ARENA_SIZE + i * ALIGNMENT : HEAP_freeListSizes[i - HEAP_NB_SMALL_FREE_LISTS], - LIST_ENTRY( heap->freeList[i].arena.entry.prev, ARENA_FREE, entry ), - LIST_ENTRY( heap->freeList[i].arena.entry.next, ARENA_FREE, entry )); + { + if (i < HEAP_NB_SMALL_FREE_LISTS) size = HEAP_MIN_ARENA_SIZE + i * ALIGNMENT; + else size = HEAP_freeListSizes[i - HEAP_NB_SMALL_FREE_LISTS]; + TRACE( " %p: size %8Ix, prev %p, next %p\n", heap->freeList + i, size, + LIST_ENTRY( heap->freeList[i].arena.entry.prev, struct entry, entry ), + LIST_ENTRY( heap->freeList[i].arena.entry.next, struct entry, entry ) ); + }
+ TRACE( " subheaps: %p\n", &heap->subheap_list ); LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { - SIZE_T freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize; - TRACE( "\n\nSub-heap %p: base=%p size=%08lx committed=%08lx\n", - subheap, subheap->base, subheap->size, subheap->commitSize ); + SIZE_T free_size = 0, used_size = 0, overhead = 0; + const char *base = subheap_base( subheap );
- TRACE( "\n Block Arena Stat Size Id\n" ); - ptr = (char *)subheap->base + subheap->headerSize; - while (ptr < (char *)subheap->base + subheap->size) + TRACE( " %p: base %p first %p last %p end %p\n", subheap, base, first_block( subheap ), + last_block( subheap ), base + subheap_size( subheap ) ); + + overhead += (char *)first_block( subheap ) - base; + for (block = first_block( subheap ); block; block = next_block( subheap, block )) { - if (*(DWORD *)ptr & ARENA_FLAG_FREE) - { - ARENA_FREE *pArena = (ARENA_FREE *)ptr; - TRACE( "%p %08x free %08x prev=%p next=%p\n", - pArena, pArena->magic, - pArena->size & ARENA_SIZE_MASK, - LIST_ENTRY( pArena->entry.prev, ARENA_FREE, entry ), - LIST_ENTRY( pArena->entry.next, ARENA_FREE, entry ) ); - ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK); - arenaSize += sizeof(ARENA_FREE); - freeSize += pArena->size & ARENA_SIZE_MASK; - } - else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE) + if (block_get_flags( block ) & ARENA_FLAG_FREE) { - ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; - TRACE( "%p %08x Used %08x back=%p\n", - pArena, pArena->magic, pArena->size & ARENA_SIZE_MASK, *((ARENA_FREE **)pArena - 1) ); - ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK); - arenaSize += sizeof(ARENA_INUSE); - usedSize += pArena->size & ARENA_SIZE_MASK; + TRACE( " %p: (free) type %#10x, size %#8x, flags %#4x, prev %p, next %p\n", block, + block_get_type( block ), block_get_size( block ), block_get_flags( block ), + LIST_ENTRY( ((struct entry *)block)->entry.prev, struct entry, entry ), + LIST_ENTRY( ((struct entry *)block)->entry.next, struct entry, entry ) ); + + overhead += block_get_overhead( block ); + free_size += block_get_size( block ) - block_get_overhead( block ); } else { - ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; - TRACE( "%p %08x %s %08x\n", - pArena, pArena->magic, pArena->magic == ARENA_INUSE_MAGIC ? "used" : "pend", - pArena->size & ARENA_SIZE_MASK ); - ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK); - arenaSize += sizeof(ARENA_INUSE); - usedSize += pArena->size & ARENA_SIZE_MASK; + TRACE( " %p: (used) type %#10x, size %#8x, flags %#4x, unused %#4x", block, + block_get_type( block ), block_get_size( block ), block_get_flags( block ), + block->unused_bytes ); + if (!(block_get_flags( block ) & ARENA_FLAG_PREV_FREE)) TRACE( "\n" ); + else TRACE( ", back %p\n", *((struct block **)block - 1) ); + + overhead += block_get_overhead( block ); + used_size += block_get_size( block ) - block_get_overhead( block ); } } - TRACE( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n", - subheap->size, subheap->commitSize, freeSize, usedSize, - arenaSize, (arenaSize * 100) / subheap->size ); + + TRACE( " total %#Ix, used %#Ix, free %#Ix, overhead %#Ix (%Iu%%)\n", used_size + free_size + overhead, + used_size, free_size, overhead, (overhead * 100) / subheap_size( subheap ) ); + } + + TRACE( " large blocks: %p\n", &heap->large_list ); + LIST_FOR_EACH_ENTRY( large, &heap->large_list, ARENA_LARGE, entry ) + { + block = (struct block *)(large + 1) - 1; + TRACE( " %p: (large) type %#10x, size %#8x, flags %#4x, total_size %#10Ix, alloc_size %#10Ix, prev %p, next %p\n", + large, block_get_type( block ), block_get_size( block ), block_get_flags( block ), large->block_size, large->data_size, + LIST_ENTRY( large->entry.prev, ARENA_LARGE, entry ), LIST_ENTRY( large->entry.next, ARENA_LARGE, entry ) ); + } + + if (heap->pending_free) + { + TRACE( " pending blocks: %p\n", heap->pending_free ); + for (i = 0; i < MAX_FREE_PENDING; ++i) + { + if (!(block = heap->pending_free[i])) break; + + TRACE( " %c%p: (pend) type %#10x, size %#8x, flags %#4x, unused %#4x", i == heap->pending_pos ? '*' : ' ', + block, block_get_type( block ), block_get_size( block ), block_get_flags( block ), block->unused_bytes ); + if (!(block_get_flags( block ) & ARENA_FLAG_PREV_FREE)) TRACE( "\n" ); + else TRACE( ", back %p\n", *((struct block **)block - 1) ); + } } }
@@ -491,7 +575,7 @@ static HEAP *HEAP_GetPtr(
if (!valid && TRACE_ON(heap)) { - HEAP_Dump( heapPtr ); + heap_dump( heapPtr ); assert( FALSE ); } } @@ -852,12 +936,12 @@ static BOOL validate_large_arena( HEAP *heap, const ARENA_LARGE *arena, BOOL qui if (quiet == NOISY) { ERR( "Heap %p: invalid large arena pointer %p\n", heap, arena ); - if (TRACE_ON(heap)) HEAP_Dump( heap ); + if (TRACE_ON(heap)) heap_dump( heap ); } else if (WARN_ON(heap)) { WARN( "Heap %p: unaligned arena pointer %p\n", heap, arena ); - if (TRACE_ON(heap)) HEAP_Dump( heap ); + if (TRACE_ON(heap)) heap_dump( heap ); } return FALSE; } @@ -867,13 +951,13 @@ static BOOL validate_large_arena( HEAP *heap, const ARENA_LARGE *arena, BOOL qui { ERR( "Heap %p: invalid large arena %p values %x/%x\n", heap, arena, arena->size, arena->magic ); - if (TRACE_ON(heap)) HEAP_Dump( heap ); + if (TRACE_ON(heap)) heap_dump( heap ); } else if (WARN_ON(heap)) { WARN( "Heap %p: invalid large arena %p values %x/%x\n", heap, arena, arena->size, arena->magic ); - if (TRACE_ON(heap)) HEAP_Dump( heap ); + if (TRACE_ON(heap)) heap_dump( heap ); } return FALSE; } @@ -1235,13 +1319,13 @@ static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE * { ERR( "Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena ); if ( TRACE_ON(heap) ) - HEAP_Dump( subheap->heap ); + heap_dump( subheap->heap ); } else if ( WARN_ON(heap) ) { WARN( "Heap %p: unaligned arena pointer %p\n", subheap->heap, pArena ); if ( TRACE_ON(heap) ) - HEAP_Dump( subheap->heap ); + heap_dump( subheap->heap ); } return FALSE; } @@ -1252,11 +1336,11 @@ static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE * if (quiet == NOISY) { ERR("Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena ); if (TRACE_ON(heap)) - HEAP_Dump( subheap->heap ); + heap_dump( subheap->heap ); } else if (WARN_ON(heap)) { WARN("Heap %p: invalid in-use arena magic %08x for %p\n", subheap->heap, pArena->magic, pArena ); if (TRACE_ON(heap)) - HEAP_Dump( subheap->heap ); + heap_dump( subheap->heap ); } return FALSE; } @@ -1328,7 +1412,7 @@ static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE * { ERR("Heap %p: free block %p overwritten at %p by %08x\n", subheap->heap, pArena + 1, ptr, *ptr ); - if (!*ptr) { HEAP_Dump( subheap->heap ); DbgBreakPoint(); } + if (!*ptr) { heap_dump( subheap->heap ); DbgBreakPoint(); } return FALSE; } ptr++;
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 424f060b719..68f7e6edcc0 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -2054,10 +2054,7 @@ static NTSTATUS heap_size( HEAP *heap, const void *ptr, SIZE_T *size ) const ARENA_LARGE *large_arena = (const ARENA_LARGE *)ptr - 1; *size = large_arena->data_size; } - else - { - *size = (block->size & ARENA_SIZE_MASK) - block->unused_bytes; - } + else *size = block_get_size( block ) - block_get_overhead( block );
return STATUS_SUCCESS; }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 68f7e6edcc0..ab9985a1016 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -608,23 +608,16 @@ static inline void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena, BOOL la }
-/*********************************************************************** - * HEAP_FindSubHeap - * Find the sub-heap containing a given address. - * - * RETURNS - * Pointer: Success - * NULL: Failure - */ -static SUBHEAP *HEAP_FindSubHeap( - const HEAP *heap, /* [in] Heap pointer */ - LPCVOID ptr ) /* [in] Address */ -{ - SUBHEAP *sub; - LIST_FOR_EACH_ENTRY( sub, &heap->subheap_list, SUBHEAP, entry ) - if ((ptr >= sub->base) && - ((const char *)ptr < (const char *)sub->base + sub->size - sizeof(ARENA_INUSE))) - return sub; +static SUBHEAP *find_subheap( const HEAP *heap, const void *ptr ) +{ + SUBHEAP *subheap; + + LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) + { + if (contains( subheap_base( subheap ), subheap_size( subheap ), ptr, sizeof(struct block) )) + return subheap; + } + return NULL; }
@@ -760,7 +753,7 @@ static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena ) mark_block_free( pArena + 1, pArena->size & ARENA_SIZE_MASK, heap->flags ); if (!prev) return; pArena = prev; - subheap = HEAP_FindSubHeap( heap, pArena ); + subheap = find_subheap( heap, pArena ); }
/* Check if we can merge with previous block */ @@ -1132,7 +1125,7 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size, sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); if (arena_size >= size) { - subheap = HEAP_FindSubHeap( heap, pArena ); + subheap = find_subheap( heap, pArena ); if (!HEAP_Commit( subheap, (ARENA_INUSE *)pArena, size )) return NULL; *ppSubHeap = subheap; return pArena; @@ -1183,7 +1176,7 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size, static BOOL HEAP_IsValidArenaPtr( const HEAP *heap, const ARENA_FREE *ptr ) { unsigned int i; - const SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr ); + const SUBHEAP *subheap = find_subheap( heap, ptr ); if (!subheap) return FALSE; if ((const char *)ptr >= (const char *)subheap->base + subheap->headerSize) return TRUE; if (subheap != &heap->subheap) return FALSE; @@ -1440,7 +1433,7 @@ static BOOL heap_validate_ptr( HEAP *heap, const void *ptr ) const ARENA_LARGE *large_arena; SUBHEAP *subheap;
- if (!(subheap = HEAP_FindSubHeap( heap, arena )) || + if (!(subheap = find_subheap( heap, arena )) || ((const char *)arena < (char *)subheap->base + subheap->headerSize)) { if (!(large_arena = find_large_block( heap, ptr ))) @@ -1495,7 +1488,7 @@ static BOOL validate_block_pointer( HEAP *heap, SUBHEAP **ret_subheap, const ARE SUBHEAP *subheap; BOOL ret = FALSE;
- if (!(*ret_subheap = subheap = HEAP_FindSubHeap( heap, arena ))) + if (!(*ret_subheap = subheap = find_subheap( heap, arena ))) { ARENA_LARGE *large_arena = find_large_block( heap, arena + 1 );
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index ab9985a1016..a917abe39af 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -250,6 +250,12 @@ static inline struct block *next_block( const SUBHEAP *subheap, const struct blo return (struct block *)next; }
+static inline BOOL check_subheap( const SUBHEAP *subheap ) +{ + const char *base = subheap->base; + return contains( base, subheap->size, base + subheap->headerSize, subheap->commitSize - subheap->headerSize ); +} + static BOOL heap_validate( HEAP *heap, BOOL quiet );
/* mark a block of memory as free for debugging purposes */ @@ -353,6 +359,7 @@ static void subheap_notify_free_all(SUBHEAP const *subheap) char const *ptr = (char const *)subheap->base + subheap->headerSize;
if (!RUNNING_ON_VALGRIND) return; + if (!check_subheap( subheap )) return;
while (ptr < (char const *)subheap->base + subheap->size) { @@ -454,6 +461,8 @@ static void heap_dump( const HEAP *heap ) TRACE( " %p: base %p first %p last %p end %p\n", subheap, base, first_block( subheap ), last_block( subheap ), base + subheap_size( subheap ) );
+ if (!check_subheap( subheap )) return; + overhead += (char *)first_block( subheap ) - base; for (block = first_block( subheap ); block; block = next_block( subheap, block )) { @@ -614,6 +623,7 @@ static SUBHEAP *find_subheap( const HEAP *heap, const void *ptr )
LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { + if (!check_subheap( subheap )) return NULL; if (contains( subheap_base( subheap ), subheap_size( subheap ), ptr, sizeof(struct block) )) return subheap; } @@ -1456,6 +1466,14 @@ static BOOL heap_validate( HEAP *heap, BOOL quiet ) LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { char *ptr = (char *)subheap->base + subheap->headerSize; + + if (!check_subheap( subheap )) + { + ERR( "heap %p, subheap %p corrupted sizes\n", heap, subheap ); + if (TRACE_ON(heap)) heap_dump( heap ); + return FALSE; + } + while (ptr < (char *)subheap->base + subheap->size) { if (*(DWORD *)ptr & ARENA_FLAG_FREE) @@ -1577,6 +1595,9 @@ static void heap_set_debug_flags( HANDLE handle ) { char *ptr = (char *)subheap->base + subheap->headerSize; char *end = (char *)subheap->base + subheap->commitSize; + + if (!check_subheap( subheap )) break; + while (ptr < end) { ARENA_INUSE *arena = (ARENA_INUSE *)ptr;
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/tests/heap.c | 92 +------------ dlls/kernelbase/memory.c | 57 +++++++- dlls/ntdll/heap.c | 276 ++++++++++++++++++------------------- 3 files changed, 191 insertions(+), 234 deletions(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 45a22adcf2e..1b8e019c0ec 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -526,7 +526,6 @@ static void test_HeapCreate(void) rtl_entry.lpData = NULL; SetLastError( 0xdeadbeef ); while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; - todo_wine ok( count == 3, "got count %lu\n", count );
count = 0; @@ -536,16 +535,13 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 3, "got count %lu\n", count );
for (i = 0; i < count; ++i) { winetest_push_context( "%Iu", i ); ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); if (!entries[i].wFlags) @@ -554,11 +550,8 @@ static void test_HeapCreate(void) ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) - { - todo_wine ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); - } else if (entries[i].wFlags & PROCESS_HEAP_REGION) { ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_REGION, "got wFlags %#x\n", rtl_entries[i].wFlags ); @@ -574,13 +567,9 @@ static void test_HeapCreate(void) winetest_pop_context(); }
- todo_wine ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); - todo_wine ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); - todo_wine ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); - todo_wine ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); todo_wine @@ -594,27 +583,20 @@ static void test_HeapCreate(void) ok( (BYTE *)entries[0].Region.lpFirstBlock == (BYTE *)entries[0].lpData + entries[0].cbData + 2 * sizeof(void *) || (BYTE *)entries[0].Region.lpFirstBlock == (BYTE *)entries[0].lpData + entries[0].cbData + 4 * sizeof(void *), "got Region.lpFirstBlock %p\n", entries[0].Region.lpFirstBlock ); - todo_wine ok( entries[0].Region.lpLastBlock == (BYTE *)entries[2].lpData + entries[2].cbData, "got Region.lpLastBlock %p\n", entries[0].Region.lpLastBlock );
ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags ); - todo_wine ok( entries[1].lpData != NULL, "got lpData %p\n", entries[1].lpData ); - todo_wine ok( entries[1].cbData != 0, "got cbData %#lx\n", entries[1].cbData ); - todo_wine ok( entries[1].cbOverhead == 4 * sizeof(void *), "got cbOverhead %#x\n", entries[1].cbOverhead ); ok( entries[1].iRegionIndex == 0, "got iRegionIndex %d\n", entries[1].iRegionIndex );
- todo_wine ok( entries[2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[2].wFlags ); - todo_wine ok( entries[2].lpData == (BYTE *)entries[0].lpData + entries[0].Region.dwCommittedSize, "got lpData %p\n", entries[2].lpData ); ok( entries[2].lpData == (BYTE *)entries[1].lpData + entries[1].cbData + 2 * entries[1].cbOverhead, "got lpData %p\n", entries[2].lpData ); - todo_wine ok( entries[2].cbData == entries[0].Region.dwUnCommittedSize - 0x1000 || entries[2].cbData == entries[0].Region.dwUnCommittedSize /* win7 */, "got cbData %#lx\n", entries[2].cbData ); @@ -630,7 +612,6 @@ static void test_HeapCreate(void) rtl_entry.lpData = NULL; SetLastError( 0xdeadbeef ); while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; - todo_wine ok( count == 4, "got count %lu\n", count );
memmove( entries + 16, entries, 3 * sizeof(entry) ); @@ -640,7 +621,6 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 4, "got count %lu\n", count ); ok( !memcmp( entries + 16, entries, 3 * sizeof(entry) ), "entries differ\n" );
@@ -648,9 +628,7 @@ static void test_HeapCreate(void) { winetest_push_context( "%Iu", i ); ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); if (!entries[i].wFlags) @@ -659,11 +637,8 @@ static void test_HeapCreate(void) ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) - { - todo_wine ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); - } else if (entries[i].wFlags & PROCESS_HEAP_REGION) { ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_REGION, "got wFlags %#x\n", rtl_entries[i].wFlags ); @@ -679,17 +654,13 @@ static void test_HeapCreate(void) winetest_pop_context(); }
- todo_wine ok( entries[3].wFlags == PROCESS_HEAP_ENTRY_BUSY || broken(entries[3].wFlags == (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_DDESHARE)) /* win7 */, "got wFlags %#x\n", entries[3].wFlags ); - todo_wine ok( entries[3].lpData == ptr, "got lpData %p\n", entries[3].lpData ); - todo_wine ok( entries[3].cbData == 5 * alloc_size, "got cbData %#lx\n", entries[3].cbData ); ok( entries[3].cbOverhead == 0 || entries[3].cbOverhead == 8 * sizeof(void *) /* win7 */, "got cbOverhead %#x\n", entries[3].cbOverhead ); - todo_wine ok( entries[3].iRegionIndex == 64, "got iRegionIndex %d\n", entries[3].iRegionIndex );
ptr1 = HeapAlloc( heap, HEAP_ZERO_MEMORY, 5 * alloc_size ); @@ -701,7 +672,6 @@ static void test_HeapCreate(void) rtl_entry.lpData = NULL; SetLastError( 0xdeadbeef ); while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; - todo_wine ok( count == 5, "got count %lu\n", count );
memmove( entries + 16, entries, 4 * sizeof(entry) ); @@ -711,7 +681,6 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 5, "got count %lu\n", count ); ok( !memcmp( entries + 16, entries, 4 * sizeof(entry) ), "entries differ\n" );
@@ -719,9 +688,7 @@ static void test_HeapCreate(void) { winetest_push_context( "%Iu", i ); ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); if (!entries[i].wFlags) @@ -730,11 +697,8 @@ static void test_HeapCreate(void) ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) - { - todo_wine ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); - } else if (entries[i].wFlags & PROCESS_HEAP_REGION) { ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_REGION, "got wFlags %#x\n", rtl_entries[i].wFlags ); @@ -750,17 +714,13 @@ static void test_HeapCreate(void) winetest_pop_context(); }
- todo_wine ok( entries[4].wFlags == PROCESS_HEAP_ENTRY_BUSY || broken(entries[4].wFlags == (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_DDESHARE)) /* win7 */, "got wFlags %#x\n", entries[4].wFlags ); - todo_wine ok( entries[4].lpData == ptr1, "got lpData %p\n", entries[4].lpData ); - todo_wine ok( entries[4].cbData == 5 * alloc_size, "got cbData %#lx\n", entries[4].cbData ); ok( entries[4].cbOverhead == 0 || entries[4].cbOverhead == 8 * sizeof(void *) /* win7 */, "got cbOverhead %#x\n", entries[4].cbOverhead ); - todo_wine ok( entries[4].iRegionIndex == 64, "got iRegionIndex %d\n", entries[4].iRegionIndex );
ret = HeapFree( heap, 0, ptr1 ); @@ -775,7 +735,6 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 3, "got count %lu\n", count ); ok( !memcmp( entries + 16, entries, 3 * sizeof(entry) ), "entries differ\n" );
@@ -789,40 +748,28 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 4, "got count %lu\n", count ); - todo_wine ok( !memcmp( entries + 16, entries, 1 * sizeof(entry) ), "entries differ\n" ); - todo_wine ok( memcmp( entries + 17, entries + 2, 2 * sizeof(entry) ), "entries differ\n" );
- todo_wine ok( entries[1].wFlags == PROCESS_HEAP_ENTRY_BUSY, "got wFlags %#x\n", entries[1].wFlags ); - todo_wine ok( entries[1].lpData == ptr, "got lpData %p\n", entries[1].lpData ); - todo_wine ok( entries[1].cbData == 123, "got cbData %#lx\n", entries[1].cbData ); ok( entries[1].cbOverhead != 0, "got cbOverhead %#x\n", entries[1].cbOverhead ); ok( entries[1].iRegionIndex == 0, "got iRegionIndex %d\n", entries[1].iRegionIndex );
ok( entries[2].wFlags == 0, "got wFlags %#x\n", entries[2].wFlags ); - todo_wine ok( entries[2].lpData == (BYTE *)entries[1].lpData + entries[1].cbData + entries[1].cbOverhead + 2 * sizeof(void *), "got lpData %p\n", entries[2].lpData ); - todo_wine ok( entries[2].cbData != 0, "got cbData %#lx\n", entries[2].cbData ); - todo_wine ok( entries[2].cbOverhead == 4 * sizeof(void *), "got cbOverhead %#x\n", entries[2].cbOverhead ); ok( entries[2].iRegionIndex == 0, "got iRegionIndex %d\n", entries[2].iRegionIndex );
- todo_wine ok( entries[3].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[3].wFlags ); - todo_wine ok( entries[3].lpData == (BYTE *)entries[0].lpData + entries[0].Region.dwCommittedSize, "got lpData %p\n", entries[3].lpData ); ok( entries[3].lpData == (BYTE *)entries[2].lpData + entries[2].cbData + 2 * entries[2].cbOverhead, "got lpData %p\n", entries[3].lpData ); - todo_wine ok( entries[3].cbData == entries[0].Region.dwUnCommittedSize - 0x1000 || entries[3].cbData == entries[0].Region.dwUnCommittedSize /* win7 */, "got cbData %#lx\n", entries[3].cbData ); @@ -839,40 +786,28 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 5, "got count %lu\n", count ); - todo_wine ok( !memcmp( entries + 16, entries, 2 * sizeof(entry) ), "entries differ\n" ); - todo_wine ok( memcmp( entries + 18, entries + 3, 2 * sizeof(entry) ), "entries differ\n" );
- todo_wine ok( entries[2].wFlags == PROCESS_HEAP_ENTRY_BUSY, "got wFlags %#x\n", entries[2].wFlags ); - todo_wine ok( entries[2].lpData == ptr1, "got lpData %p\n", entries[2].lpData ); - todo_wine ok( entries[2].cbData == 456, "got cbData %#lx\n", entries[2].cbData ); ok( entries[2].cbOverhead != 0, "got cbOverhead %#x\n", entries[2].cbOverhead ); ok( entries[2].iRegionIndex == 0, "got iRegionIndex %d\n", entries[2].iRegionIndex );
ok( entries[3].wFlags == 0, "got wFlags %#x\n", entries[3].wFlags ); - todo_wine ok( entries[3].lpData == (BYTE *)entries[2].lpData + entries[2].cbData + entries[2].cbOverhead + 2 * sizeof(void *), "got lpData %p\n", entries[3].lpData ); - todo_wine ok( entries[3].cbData != 0, "got cbData %#lx\n", entries[3].cbData ); - todo_wine ok( entries[3].cbOverhead == 4 * sizeof(void *), "got cbOverhead %#x\n", entries[3].cbOverhead ); ok( entries[3].iRegionIndex == 0, "got iRegionIndex %d\n", entries[3].iRegionIndex );
- todo_wine ok( entries[4].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[4].wFlags ); - todo_wine ok( entries[4].lpData == (BYTE *)entries[0].lpData + entries[0].Region.dwCommittedSize, "got lpData %p\n", entries[4].lpData ); ok( entries[4].lpData == (BYTE *)entries[3].lpData + entries[3].cbData + 2 * entries[3].cbOverhead, "got lpData %p\n", entries[4].lpData ); - todo_wine ok( entries[4].cbData == entries[0].Region.dwUnCommittedSize - 0x1000 || entries[4].cbData == entries[0].Region.dwUnCommittedSize /* win7 */, "got cbData %#lx\n", entries[4].cbData ); @@ -1004,21 +939,14 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); - todo_wine ok( count == 3, "got count %lu\n", count );
- todo_wine ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); - todo_wine ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); - todo_wine ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); - todo_wine ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); - todo_wine ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags ); - todo_wine ok( entries[2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[2].wFlags );
for (i = 0; i < 0x12; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); @@ -1035,16 +963,11 @@ static void test_HeapCreate(void) ok( count > 24, "got count %lu\n", count ); if (count < 2) count = 2;
- todo_wine ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); - todo_wine ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); - todo_wine ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); - todo_wine ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); - todo_wine ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags );
for (i = 0; i < 0x12; i++) @@ -1060,10 +983,7 @@ static void test_HeapCreate(void) if (entries[count - 1].wFlags == PROCESS_HEAP_REGION) /* > win7 */ ok( entries[count - 2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[count - 2].wFlags ); else - { - todo_wine ok( entries[count - 1].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[count - 2].wFlags ); - }
count = 0; memset( &rtl_entries, 0, sizeof(rtl_entries) ); @@ -1079,9 +999,7 @@ static void test_HeapCreate(void) { winetest_push_context( "%Iu", i ); ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); if (!entries[i].wFlags) @@ -1120,12 +1038,9 @@ static void test_HeapCreate(void) ok( count > 24, "got count %lu\n", count ); if (count < 2) count = 2;
- todo_wine ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); - todo_wine ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); - todo_wine ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); ok( entries[1].wFlags == 0 || entries[1].wFlags == PROCESS_HEAP_ENTRY_BUSY /* win7 */, "got wFlags %#x\n", entries[1].wFlags ); @@ -1133,8 +1048,8 @@ static void test_HeapCreate(void) for (i = 1; i < count - 2; i++) { if (entries[i].wFlags != PROCESS_HEAP_ENTRY_BUSY) continue; - todo_wine_if( sizeof(void *) == 8 ) ok( entries[i].cbData == 0x18 + 2 * sizeof(void *), "got cbData %#lx\n", entries[i].cbData ); + todo_wine_if(sizeof(void *) == 8) ok( entries[i].cbOverhead == 0x8, "got cbOverhead %#x\n", entries[i].cbOverhead ); }
@@ -1157,9 +1072,7 @@ static void test_HeapCreate(void) { winetest_push_context( "%Iu", i ); ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); - todo_wine_if(sizeof(void *) == 8) ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); if (!entries[i].wFlags) @@ -1171,11 +1084,8 @@ static void test_HeapCreate(void) "got wFlags %#x\n", rtl_entries[i].wFlags ); } else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) - { - todo_wine ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, "got wFlags %#x\n", rtl_entries[i].wFlags ); - } else if (entries[i].wFlags & PROCESS_HEAP_REGION) { ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_LFH|RTL_HEAP_ENTRY_REGION), "got wFlags %#x\n", rtl_entries[i].wFlags ); diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 35e6d4e3b8c..656569220fa 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -601,12 +601,67 @@ BOOL WINAPI DECLSPEC_HOTPATCH HeapValidate( HANDLE heap, DWORD flags, LPCVOID pt }
+/* undocumented RtlWalkHeap structure */ + +struct rtl_heap_entry +{ + LPVOID lpData; + SIZE_T cbData; /* differs from PROCESS_HEAP_ENTRY */ + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; /* value differs from PROCESS_HEAP_ENTRY */ + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + }; +}; + +/* rtl_heap_entry flags, names made up */ + +#define RTL_HEAP_ENTRY_BUSY 0x0001 +#define RTL_HEAP_ENTRY_REGION 0x0002 +#define RTL_HEAP_ENTRY_BLOCK 0x0010 +#define RTL_HEAP_ENTRY_UNCOMMITTED 0x1000 +#define RTL_HEAP_ENTRY_COMMITTED 0x4000 +#define RTL_HEAP_ENTRY_LFH 0x8000 + + /*********************************************************************** * HeapWalk (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH HeapWalk( HANDLE heap, PROCESS_HEAP_ENTRY *entry ) { - return set_ntstatus( RtlWalkHeap( heap, entry )); + struct rtl_heap_entry rtl_entry = {.lpData = entry->lpData}; + NTSTATUS status; + + if (!(status = RtlWalkHeap( heap, &rtl_entry ))) + { + entry->lpData = rtl_entry.lpData; + entry->cbData = rtl_entry.cbData; + entry->cbOverhead = rtl_entry.cbOverhead; + entry->iRegionIndex = rtl_entry.iRegionIndex; + + if (rtl_entry.wFlags & RTL_HEAP_ENTRY_BUSY) + entry->wFlags = PROCESS_HEAP_ENTRY_BUSY; + else if (rtl_entry.wFlags & RTL_HEAP_ENTRY_REGION) + entry->wFlags = PROCESS_HEAP_REGION; + else if (rtl_entry.wFlags & RTL_HEAP_ENTRY_UNCOMMITTED) + entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE; + else + entry->wFlags = 0; + + memcpy( &entry->u.Region, &rtl_entry.Region, sizeof(entry->u.Region) ); + } + + return set_ntstatus( status ); }
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index a917abe39af..255a3850c70 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -39,6 +39,39 @@
WINE_DEFAULT_DEBUG_CHANNEL(heap);
+/* undocumented RtlWalkHeap structure */ + +struct rtl_heap_entry +{ + LPVOID lpData; + SIZE_T cbData; /* differs from PROCESS_HEAP_ENTRY */ + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; /* value differs from PROCESS_HEAP_ENTRY */ + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + }; +}; + +/* rtl_heap_entry flags, names made up */ + +#define RTL_HEAP_ENTRY_BUSY 0x0001 +#define RTL_HEAP_ENTRY_REGION 0x0002 +#define RTL_HEAP_ENTRY_BLOCK 0x0010 +#define RTL_HEAP_ENTRY_UNCOMMITTED 0x1000 +#define RTL_HEAP_ENTRY_COMMITTED 0x4000 +#define RTL_HEAP_ENTRY_LFH 0x8000 + + /* header for heap blocks */
typedef struct block @@ -517,46 +550,13 @@ static void heap_dump( const HEAP *heap ) } }
- -static void HEAP_DumpEntry( LPPROCESS_HEAP_ENTRY entry ) +static const char *debugstr_heap_entry( struct rtl_heap_entry *entry ) { - WORD rem_flags; - TRACE( "Dumping entry %p\n", entry ); - TRACE( "lpData\t\t: %p\n", entry->lpData ); - TRACE( "cbData\t\t: %08x\n", entry->cbData); - TRACE( "cbOverhead\t: %08x\n", entry->cbOverhead); - TRACE( "iRegionIndex\t: %08x\n", entry->iRegionIndex); - TRACE( "WFlags\t\t: "); - if (entry->wFlags & PROCESS_HEAP_REGION) - TRACE( "PROCESS_HEAP_REGION "); - if (entry->wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) - TRACE( "PROCESS_HEAP_UNCOMMITTED_RANGE "); - if (entry->wFlags & PROCESS_HEAP_ENTRY_BUSY) - TRACE( "PROCESS_HEAP_ENTRY_BUSY "); - if (entry->wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) - TRACE( "PROCESS_HEAP_ENTRY_MOVEABLE "); - if (entry->wFlags & PROCESS_HEAP_ENTRY_DDESHARE) - TRACE( "PROCESS_HEAP_ENTRY_DDESHARE "); - rem_flags = entry->wFlags & - ~(PROCESS_HEAP_REGION | PROCESS_HEAP_UNCOMMITTED_RANGE | - PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_MOVEABLE| - PROCESS_HEAP_ENTRY_DDESHARE); - if (rem_flags) - TRACE( "Unknown %08x", rem_flags); - TRACE( "\n"); - if ((entry->wFlags & PROCESS_HEAP_ENTRY_BUSY ) - && (entry->wFlags & PROCESS_HEAP_ENTRY_MOVEABLE)) - { - /* Treat as block */ - TRACE( "BLOCK->hMem\t\t:%p\n", entry->u.Block.hMem); - } - if (entry->wFlags & PROCESS_HEAP_REGION) - { - TRACE( "Region.dwCommittedSize\t:%08x\n",entry->u.Region.dwCommittedSize); - TRACE( "Region.dwUnCommittedSize\t:%08x\n",entry->u.Region.dwUnCommittedSize); - TRACE( "Region.lpFirstBlock\t:%p\n",entry->u.Region.lpFirstBlock); - TRACE( "Region.lpLastBlock\t:%p\n",entry->u.Region.lpLastBlock); - } + const char *str = wine_dbg_sprintf( "data %p, size %#Ix, overhead %#x, region %#x, flags %#x", entry->lpData, + entry->cbData, entry->cbOverhead, entry->iRegionIndex, entry->wFlags ); + if (!(entry->wFlags & RTL_HEAP_ENTRY_REGION)) return str; + return wine_dbg_sprintf( "%s, commit %#x, uncommit %#x, first %p, last %p", str, entry->Region.dwCommittedSize, + entry->Region.dwUnCommittedSize, entry->Region.lpFirstBlock, entry->Region.lpLastBlock ); }
/*********************************************************************** @@ -916,7 +916,7 @@ static void *realloc_large_block( HEAP *heap, DWORD flags, void *ptr, SIZE_T siz /*********************************************************************** * find_large_block */ -static ARENA_LARGE *find_large_block( HEAP *heap, const void *ptr ) +static ARENA_LARGE *find_large_block( const HEAP *heap, const void *ptr ) { ARENA_LARGE *arena;
@@ -2120,131 +2120,123 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, const void *ptr ) }
-/*********************************************************************** - * RtlWalkHeap (NTDLL.@) - * - * FIXME - * The PROCESS_HEAP_ENTRY flag values seem different between this - * function and HeapWalk(). To be checked. - */ -NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr ) +static NTSTATUS heap_walk_blocks( const HEAP *heap, const SUBHEAP *subheap, struct rtl_heap_entry *entry ) { - LPPROCESS_HEAP_ENTRY entry = entry_ptr; /* FIXME */ - HEAP *heapPtr = HEAP_GetPtr(heap); - SUBHEAP *sub, *currentheap = NULL; - NTSTATUS ret; - char *ptr; - int region_index = 0; - - if (!heapPtr || !entry) return STATUS_INVALID_PARAMETER; - - heap_lock( heapPtr, 0 ); + const char *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap ), *end = base + subheap_size( subheap ); + const struct block *block, *blocks = first_block( subheap );
- /* FIXME: enumerate large blocks too */ + if (entry->lpData == commit_end) return STATUS_NO_MORE_ENTRIES;
- /* set ptr to the next arena to be examined */ + if (entry->lpData == base) block = blocks; + else if (!(block = next_block( subheap, (struct block *)entry->lpData - 1 ))) + { + entry->lpData = (void *)commit_end; + entry->cbData = end - commit_end; + entry->cbOverhead = 0; + entry->iRegionIndex = 0; + entry->wFlags = RTL_HEAP_ENTRY_UNCOMMITTED; + return STATUS_SUCCESS; + }
- if (!entry->lpData) /* first call (init) ? */ + if (block_get_flags( block ) & ARENA_FLAG_FREE) { - TRACE("begin walking of heap %p.\n", heap); - currentheap = &heapPtr->subheap; - ptr = (char*)currentheap->base + currentheap->headerSize; + entry->lpData = (char *)block + block_get_overhead( block ); + entry->cbData = block_get_size( block ) - block_get_overhead( block ); + /* FIXME: last free block should not include uncommitted range, which also has its own overhead */ + if (!contains( blocks, commit_end - (char *)blocks, block, block_get_size( block ) )) + entry->cbData = commit_end - (char *)entry->lpData - 8 * sizeof(void *); + entry->cbOverhead = 4 * sizeof(void *); + entry->iRegionIndex = 0; + entry->wFlags = 0; } else { - ptr = entry->lpData; - LIST_FOR_EACH_ENTRY( sub, &heapPtr->subheap_list, SUBHEAP, entry ) - { - if ((ptr >= (char *)sub->base) && - (ptr < (char *)sub->base + sub->size)) - { - currentheap = sub; - break; - } - region_index++; - } - if (currentheap == NULL) - { - ERR("no matching subheap found, shouldn't happen !\n"); - ret = STATUS_NO_MORE_ENTRIES; - goto HW_end; - } - - if (((ARENA_INUSE *)ptr - 1)->magic == ARENA_INUSE_MAGIC || - ((ARENA_INUSE *)ptr - 1)->magic == ARENA_PENDING_MAGIC) - { - ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1; - ptr += pArena->size & ARENA_SIZE_MASK; - } - else if (((ARENA_FREE *)ptr - 1)->magic == ARENA_FREE_MAGIC) - { - ARENA_FREE *pArena = (ARENA_FREE *)ptr - 1; - ptr += pArena->size & ARENA_SIZE_MASK; - } - else - ptr += entry->cbData; /* point to next arena */ - - if (ptr > (char *)currentheap->base + currentheap->size - 1) - { /* proceed with next subheap */ - struct list *next = list_next( &heapPtr->subheap_list, ¤theap->entry ); - if (!next) - { /* successfully finished */ - TRACE("end reached.\n"); - ret = STATUS_NO_MORE_ENTRIES; - goto HW_end; - } - currentheap = LIST_ENTRY( next, SUBHEAP, entry ); - ptr = (char *)currentheap->base + currentheap->headerSize; - } + entry->lpData = (void *)(block + 1); + entry->cbData = block_get_size( block ) - block_get_overhead( block ); + entry->cbOverhead = block_get_overhead( block ); + entry->iRegionIndex = 0; + entry->wFlags = RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY; }
- entry->wFlags = 0; - if (*(DWORD *)ptr & ARENA_FLAG_FREE) - { - ARENA_FREE *pArena = (ARENA_FREE *)ptr; + return STATUS_SUCCESS; +}
- /*TRACE("free, magic: %04x\n", pArena->magic);*/ +static NTSTATUS heap_walk( const HEAP *heap, struct rtl_heap_entry *entry ) +{ + const ARENA_LARGE *large; + const struct list *next; + const SUBHEAP *subheap; + NTSTATUS status; + char *base;
- entry->lpData = pArena + 1; - entry->cbData = pArena->size & ARENA_SIZE_MASK; - entry->cbOverhead = sizeof(ARENA_FREE); - entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE; + if ((large = find_large_block( heap, entry->lpData ))) + next = &large->entry; + else if ((subheap = find_subheap( heap, entry->lpData ))) + { + if (!(status = heap_walk_blocks( heap, subheap, entry ))) return STATUS_SUCCESS; + else if (status != STATUS_NO_MORE_ENTRIES) return status; + next = &subheap->entry; } else { - ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; + if (entry->lpData) return STATUS_INVALID_PARAMETER; + next = &heap->subheap_list; + }
- /*TRACE("busy, magic: %04x\n", pArena->magic);*/ + if (!large && (next = list_next( &heap->subheap_list, next ))) + { + subheap = LIST_ENTRY( next, SUBHEAP, entry ); + base = subheap_base( subheap ); + entry->lpData = base; + entry->cbData = (char *)first_block( subheap ) - base; + entry->cbOverhead = 0; + entry->iRegionIndex = 0; + entry->wFlags = RTL_HEAP_ENTRY_REGION; + entry->Region.dwCommittedSize = (char *)subheap_commit_end( subheap ) - base; + entry->Region.dwUnCommittedSize = subheap_size( subheap ) - entry->Region.dwCommittedSize; + entry->Region.lpFirstBlock = base + entry->cbData; + entry->Region.lpLastBlock = base + subheap_size( subheap ); + return STATUS_SUCCESS; + }
- entry->lpData = pArena + 1; - entry->cbData = pArena->size & ARENA_SIZE_MASK; - entry->cbOverhead = sizeof(ARENA_INUSE); - entry->wFlags = (pArena->magic == ARENA_PENDING_MAGIC) ? - PROCESS_HEAP_UNCOMMITTED_RANGE : PROCESS_HEAP_ENTRY_BUSY; - /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE - and PROCESS_HEAP_ENTRY_DDESHARE yet */ + if (!next) next = &heap->large_list; + if ((next = list_next( &heap->large_list, next ))) + { + large = LIST_ENTRY( next, ARENA_LARGE, entry ); + entry->lpData = (void *)(large + 1); + entry->cbData = large->data_size; + entry->cbOverhead = 0; + entry->iRegionIndex = 64; + entry->wFlags = RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY; + return STATUS_SUCCESS; }
- entry->iRegionIndex = region_index; + return STATUS_NO_MORE_ENTRIES; +} + +/*********************************************************************** + * RtlWalkHeap (NTDLL.@) + */ +NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, void *entry_ptr ) +{ + struct rtl_heap_entry *entry = entry_ptr; + NTSTATUS status; + HEAP *heapPtr;
- /* first element of heap ? */ - if (ptr == (char *)currentheap->base + currentheap->headerSize) + if (!entry) return STATUS_INVALID_PARAMETER; + + if (!(heapPtr = HEAP_GetPtr(heap))) + status = STATUS_INVALID_HANDLE; + else { - entry->wFlags |= PROCESS_HEAP_REGION; - entry->u.Region.dwCommittedSize = currentheap->commitSize; - entry->u.Region.dwUnCommittedSize = - currentheap->size - currentheap->commitSize; - entry->u.Region.lpFirstBlock = /* first valid block */ - (char *)currentheap->base + currentheap->headerSize; - entry->u.Region.lpLastBlock = /* first invalid block */ - (char *)currentheap->base + currentheap->size; + heap_lock( heapPtr, 0 ); + status = heap_walk( heapPtr, entry ); + heap_unlock( heapPtr, 0 ); } - ret = STATUS_SUCCESS; - if (TRACE_ON(heap)) HEAP_DumpEntry(entry);
-HW_end: - heap_unlock( heapPtr, 0 ); - return ret; + TRACE( "heap %p, entry %p %s, return %#x\n", heap, entry, + status ? "<empty>" : debugstr_heap_entry(entry), status ); + return status; }