From 074177b8b0356df2e3ddfb8534e2ee1257b37a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 5 May 2022 00:49:25 +0200 Subject: [PATCH] ntdll: Rewrite RtlWalkHeap and enumerate large blocks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RĂ©mi Bernon Signed-off-by: Alexandre Julliard --- dlls/kernel32/tests/heap.c | 92 +---------- dlls/kernelbase/memory.c | 57 ++++++- dlls/ntdll/heap.c | 302 ++++++++++++++++++------------------- 3 files changed, 204 insertions(+), 247 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 ) } +static NTSTATUS heap_walk_blocks( const HEAP *heap, const SUBHEAP *subheap, struct rtl_heap_entry *entry ) +{ + 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 ); + + if (entry->lpData == commit_end) return STATUS_NO_MORE_ENTRIES; + + 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 (block_get_flags( block ) & ARENA_FLAG_FREE) + { + 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 + { + 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; + } + + return STATUS_SUCCESS; +} + +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; + + 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 + { + if (entry->lpData) return STATUS_INVALID_PARAMETER; + next = &heap->subheap_list; + } + + 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; + } + + 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; + } + + return STATUS_NO_MORE_ENTRIES; +} + /*********************************************************************** * 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 ) +NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, void *entry_ptr ) { - LPPROCESS_HEAP_ENTRY entry = entry_ptr; /* FIXME */ - HEAP *heapPtr = HEAP_GetPtr(heap); - SUBHEAP *sub, *currentheap = NULL; - NTSTATUS ret; - char *ptr; - int region_index = 0; + struct rtl_heap_entry *entry = entry_ptr; + NTSTATUS status; + HEAP *heapPtr; - if (!heapPtr || !entry) return STATUS_INVALID_PARAMETER; + if (!entry) return STATUS_INVALID_PARAMETER; - heap_lock( heapPtr, 0 ); - - /* FIXME: enumerate large blocks too */ - - /* set ptr to the next arena to be examined */ - - if (!entry->lpData) /* first call (init) ? */ - { - TRACE("begin walking of heap %p.\n", heap); - currentheap = &heapPtr->subheap; - ptr = (char*)currentheap->base + currentheap->headerSize; - } + if (!(heapPtr = HEAP_GetPtr(heap))) + status = STATUS_INVALID_HANDLE; 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; - } + heap_lock( heapPtr, 0 ); + status = heap_walk( heapPtr, entry ); + heap_unlock( heapPtr, 0 ); } - entry->wFlags = 0; - if (*(DWORD *)ptr & ARENA_FLAG_FREE) - { - ARENA_FREE *pArena = (ARENA_FREE *)ptr; - - /*TRACE("free, magic: %04x\n", pArena->magic);*/ - - entry->lpData = pArena + 1; - entry->cbData = pArena->size & ARENA_SIZE_MASK; - entry->cbOverhead = sizeof(ARENA_FREE); - entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE; - } - else - { - ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; - - /*TRACE("busy, magic: %04x\n", pArena->magic);*/ - - 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 */ - } - - entry->iRegionIndex = region_index; - - /* first element of heap ? */ - if (ptr == (char *)currentheap->base + currentheap->headerSize) - { - 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; - } - 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 ? "" : debugstr_heap_entry(entry), status ); + return status; }