From: Julius Bettin julius.bettin@protonmail.com
--- dlls/kernel32/kernel32.spec | 2 +- dlls/kernel32/tests/heap.c | 52 +++++++++++++++++++++++++++++ dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/memory.c | 58 +++++++++++++++++++++++++++++++++ include/minwinbase.h | 9 +++++ include/winbase.h | 1 + 6 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index caa6c92b653..ff3bdc67b21 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -957,7 +957,7 @@ @ stub HeapSetFlags @ stdcall -import HeapSetInformation(ptr long ptr long) @ stdcall HeapSize(long long ptr) NTDLL.RtlSizeHeap -@ stub HeapSummary +@ stdcall -import HeapSummary(long long ptr) @ stdcall -import HeapUnlock(long) @ stub HeapUsage @ stdcall -import HeapValidate(long long ptr) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index c62eb449192..64327352622 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -3740,6 +3740,56 @@ static void test_heap_sizes(void) } }
+static void test_HeapSummary(void) +{ + HANDLE heap; + HEAP_SUMMARY heap_summary; + BOOL ret; + DWORD err; + void *p; + + /* setup */ + + heap = HeapCreate( 0, 0, 0 ); /* growable heap */ + ok( heap != NULL, "creation failed\n" ); + + HeapAlloc( heap , 0, 0x100 ); + HeapAlloc( heap , 0, 0x200 ); + p = HeapAlloc( heap , 0, 0x300 ); + HeapAlloc( heap, 0, 0x60000 ); + HeapFree( heap, 0, p ); + + memset( &heap_summary, 0, sizeof(heap_summary) ); + + /* test cases */ + + ret = HeapSummary( heap, 0, &heap_summary ); + err = GetLastError(); + ok( !ret, "HeapSummary() with cb != sizeof(HEAP_SUMMARY) returned TRUE\n" ); + ok( err == ERROR_INVALID_PARAMETER, + "HeapSummary() with cb != sizeof(HEAP_SUMMARY) set last error to %lu\n", err ); + + heap_summary.cb = sizeof(heap_summary); + SetLastError( ERROR_INVALID_HANDLE ); /* set to known value */ + ret = HeapSummary( heap, 0, &heap_summary ); + err = GetLastError(); + ok( ret, "HeapSummary() returned FALSE\n" ); + ok( err == ERROR_INVALID_HANDLE, "HeapSummary() set last error on success to %lu\n", err ); + + ok( heap_summary.cbAllocated == 0x100 + 0x200 + 0x60000, + "HeapSummary: wrong cbAllocated value %#Ix\n", heap_summary.cbAllocated ); + ok( heap_summary.cbCommitted >= heap_summary.cbAllocated, + "HeapSummary: cbCommitted %#Ix < cbAllocated %#Ix\n", + heap_summary.cbCommitted, heap_summary.cbAllocated ); + ok( heap_summary.cbReserved >= heap_summary.cbCommitted, + "HeapSummary: cbReserved %#Ix < cbCommitted %#Ix\n", + heap_summary.cbReserved, heap_summary.cbCommitted ); + + /* cleanup */ + + HeapDestroy( heap ); +} + START_TEST(heap) { int argc; @@ -3777,4 +3827,6 @@ START_TEST(heap) } else win_skip( "RtlGetNtGlobalFlags not found, skipping heap debug tests\n" ); test_heap_sizes(); + + test_HeapSummary(); } diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index fd9868fb69e..545c30a1eb8 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -821,7 +821,7 @@ @ stdcall HeapReAlloc(long long ptr long) ntdll.RtlReAllocateHeap @ stdcall HeapSetInformation(ptr long ptr long) @ stdcall HeapSize(long long ptr) ntdll.RtlSizeHeap -@ stub HeapSummary +@ stdcall HeapSummary(long long ptr) @ stdcall HeapUnlock(long) @ stdcall HeapValidate(long long ptr) @ stdcall HeapWalk(long ptr) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 39018012199..955e1d5b7c1 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -777,6 +777,64 @@ BOOL WINAPI HeapSetInformation( HANDLE heap, HEAP_INFORMATION_CLASS infoclass, P }
+/*********************************************************************** + * HeapSummary (kernelbase.@) + */ +BOOL WINAPI HeapSummary( HANDLE heap, DWORD flags, LPHEAP_SUMMARY heap_summary ) +{ + DWORD last_error = GetLastError(); + SIZE_T allocated = 0; + SIZE_T committed = 0; + SIZE_T uncommitted = 0; + PROCESS_HEAP_ENTRY entry; + + if (heap_summary->cb != sizeof(*heap_summary)) + { + /* needs to be set to the exact size by the caller */ + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + memset( &entry, 0, sizeof(entry) ); + + if (!HeapLock( heap )) + return FALSE; + + while (HeapWalk( heap, &entry )) + { + if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) + { + allocated += entry.cbData; + } + else if (entry.wFlags & PROCESS_HEAP_REGION) + { + committed += entry.Region.dwCommittedSize; + uncommitted += entry.Region.dwUnCommittedSize; + } + } + + if (GetLastError() != ERROR_NO_MORE_ITEMS) + { + /* HeapWalk unsuccessful */ + (void) HeapUnlock( heap ); + return FALSE; + } + + if (!HeapUnlock( heap )) + return FALSE; + + heap_summary->cbAllocated = allocated; + heap_summary->cbCommitted = committed; + heap_summary->cbReserved = committed + uncommitted; + heap_summary->cbMaxReserve = heap_summary->cbReserved; + + /* restore previous last error on success to make it look + unchanged for the caller. */ + SetLastError(last_error); + return TRUE; +} + + /*********************************************************************** * HeapUnlock (kernelbase.@) */ diff --git a/include/minwinbase.h b/include/minwinbase.h index 86938533374..a8d2dc4d086 100644 --- a/include/minwinbase.h +++ b/include/minwinbase.h @@ -143,6 +143,15 @@ typedef struct _PROCESS_HEAP_ENTRY #define PROCESS_HEAP_ENTRY_MOVEABLE 0x0010 #define PROCESS_HEAP_ENTRY_DDESHARE 0x0020
+typedef struct _HEAP_SUMMARY +{ + DWORD cb; + SIZE_T cbAllocated; + SIZE_T cbCommitted; + SIZE_T cbReserved; + SIZE_T cbMaxReserve; +} HEAP_SUMMARY, *PHEAP_SUMMARY, *LPHEAP_SUMMARY; + typedef enum _GET_FILEEX_INFO_LEVELS { GetFileExInfoStandard } GET_FILEEX_INFO_LEVELS; diff --git a/include/winbase.h b/include/winbase.h index f75b7503e41..1bbfd1a31a6 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2089,6 +2089,7 @@ WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE,DWORD,LPCVOID); WINBASEAPI BOOL WINAPI HeapUnlock(HANDLE); WINBASEAPI BOOL WINAPI HeapValidate(HANDLE,DWORD,LPCVOID); WINBASEAPI BOOL WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY); +WINBASEAPI BOOL WINAPI HeapSummary(HANDLE,DWORD,LPHEAP_SUMMARY); WINBASEAPI BOOL WINAPI InitAtomTable(DWORD); WINADVAPI BOOL WINAPI InitializeAcl(PACL,DWORD,DWORD); WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE);