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