Rémi Bernon : ntdll: Fixup the RtlWalkHeap entry pointer before subheap lookup.

Alexandre Julliard julliard at winehq.org
Tue Jul 26 15:40:52 CDT 2022


Module: wine
Branch: master
Commit: 1d65bc06b303dc19307c1a1c26603d690ffa7f12
URL:    https://gitlab.winehq.org/wine/wine/-/commit/1d65bc06b303dc19307c1a1c26603d690ffa7f12

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Mon Jul 25 18:35:56 2022 +0200

ntdll: Fixup the RtlWalkHeap entry pointer before subheap lookup.

The commit end of a subheap may be equal to the beginning of another
subheap, in which case find_subheap() will return that one, when we pass
it the previously returned uncommitted range lpData, and we may
effectively skip backwards in the subheap list.

This fixes a hang on starting or loading a game with Bloodrayne:
Terminal Cut.

Based on a patch from Zebediah Figura.

---

 dlls/ntdll/heap.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index 4d39291bdb8..ef91096f258 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -1812,17 +1812,13 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE handle, ULONG flags, const void *ptr )
 }
 
 
-static NTSTATUS heap_walk_blocks( const struct heap *heap, const SUBHEAP *subheap, struct rtl_heap_entry *entry )
+static NTSTATUS heap_walk_blocks( const struct heap *heap, const SUBHEAP *subheap,
+                                  const struct block *block, 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 );
-    char *data = entry->lpData;
+    const struct block *blocks = first_block( subheap );
 
     if (entry->lpData == commit_end) return STATUS_NO_MORE_ENTRIES;
-
-    if (entry->wFlags & RTL_HEAP_ENTRY_BUSY) block = (struct block *)data - 1;
-    else block = (struct block *)(data - sizeof(struct list)) - 1;
-
     if (entry->lpData == base) block = blocks;
     else if (!(block = next_block( subheap, block )))
     {
@@ -1859,21 +1855,26 @@ static NTSTATUS heap_walk_blocks( const struct heap *heap, const SUBHEAP *subhea
 
 static NTSTATUS heap_walk( const struct heap *heap, struct rtl_heap_entry *entry )
 {
-    const struct block *block = (struct block *)entry->lpData - 1;
+    const char *data = entry->lpData;
     const ARENA_LARGE *large = NULL;
+    const struct block *block;
     const struct list *next;
     const SUBHEAP *subheap;
     NTSTATUS status;
     char *base;
 
+    if (!data || entry->wFlags & RTL_HEAP_ENTRY_REGION) block = (struct block *)data;
+    else if (entry->wFlags & RTL_HEAP_ENTRY_BUSY) block = (struct block *)data - 1;
+    else block = (struct block *)(data - sizeof(struct list)) - 1;
+
     if (find_large_block( heap, block ))
     {
         large = CONTAINING_RECORD( block, ARENA_LARGE, block );
         next = &large->entry;
     }
-    else if ((subheap = find_subheap( heap, entry->lpData, TRUE )))
+    else if ((subheap = find_subheap( heap, block, TRUE )))
     {
-        if (!(status = heap_walk_blocks( heap, subheap, entry ))) return STATUS_SUCCESS;
+        if (!(status = heap_walk_blocks( heap, subheap, block, entry ))) return STATUS_SUCCESS;
         else if (status != STATUS_NO_MORE_ENTRIES) return status;
         next = &subheap->entry;
     }




More information about the wine-cvs mailing list