https://bugs.winehq.org/show_bug.cgi?id=55842
Bug ID: 55842 Summary: Neverwinter Nights 2 Complete (GOG.com) crashes while starting a new game from the menu Product: Wine Version: 8.18 Hardware: x86-64 OS: Linux Status: NEW Keywords: regression Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: gyebro69@gmail.com CC: pgofman@codeweavers.com Regression SHA1: 059094c1c18ddc33b04eac53a72fd0eb7510be94 Distribution: ---
Created attachment 75340 --> https://bugs.winehq.org/attachment.cgi?id=75340 terminal output
Neverwinter Nights 2 Complete from GOG.com loads to the menu properly but crashes when I load a previously saved game or start a new campaign. The game version is 1.23.1765.
Used to work until
commit 059094c1c18ddc33b04eac53a72fd0eb7510be94 Author: Paul Gofman pgofman@codeweavers.com Date: Thu Oct 19 18:46:13 2023 -0600
ntdll: Define heap block's BLOCK_FLAG_LFH as 0x80.
Reverting the patch on top of current git fixes the problem for me.
No demo version is available.
wine-8.18-225-gd1d13e50ec5
https://bugs.winehq.org/show_bug.cgi?id=55842
--- Comment #1 from Paul Gofman pgofman@codeweavers.com --- Thanks for bisecting. I could reproduce the crash with the game.
While attribution to the blamed commit is not exactly random, the problem is pre-existing (probably since the introduction of LFH heap) and the game essentially worked by chance before the blamed commit.
What is a bit specific with the game is that it uses msvcr80._set_sbh_threshold() which triggers the use of a separate heap in msvcr80.msvcrt_heap_alloc(). Then, msvcrt_heap_free() uses HeapValidate() to guess the correct heap:
----- static BOOL msvcrt_heap_free(void *ptr) { if(sb_heap && ptr && !HeapValidate(heap, 0, ptr)) { void **saved = SAVED_PTR(ptr); return HeapFree(sb_heap, 0, *saved); }
return HeapFree(heap, 0, ptr); } -----
The actual problem is that RtlValidateHeap() doesn't work correctly for LFH blocks placed in large blocks which can happen for bigger LFH block bin sizes. Not the most frequent occasion actually but happens with the game, and once during loading it gets LFH block of size 0x4000 allocated this way. Once HeapValidate failed in msvcrt_heap_free for this block (for the correct block without any heap corruption), msvcrt_heap_free dereferences ptr - 4 to free that pointer with HeapFree from another heap. That's where blamed commit comes in. Before that the thing was lucky and was getting the value from (ptr - 4) which could be dereferenced (to some random "pointer"), then HeapFree() was failing to free it (leaking memory) but not crashing allowing the game continue. With the blamed commit the value before ptr has expectedly change and now dereferencing that crashes in msvcrt_heap_free.
I sent a MR which is fixing the true problem (failing HeapValidate): https://gitlab.winehq.org/wine/wine/-/merge_requests/4232
https://bugs.winehq.org/show_bug.cgi?id=55842
Béla Gyebrószki gyebro69@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |RESOLVED Fixed by SHA1| |1063cf81967c0929d7f08ff53d5 | |42b56209732e0 Resolution|--- |FIXED
--- Comment #2 from Béla Gyebrószki gyebro69@gmail.com --- Fixed by https://source.winehq.org/git/wine.git/commit/1063cf81967c0929d7f08ff53d542b...
Thank you, Paul Gofman.
https://bugs.winehq.org/show_bug.cgi?id=55842
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #3 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 8.20.