[PATCH] ntdll: Only call wine exception handlers on the current stack.

Rémi Bernon rbernon at codeweavers.com
Tue Feb 1 06:49:30 CST 2022


On 2/1/22 13:25, Paul Gofman wrote:
> On 2/1/22 14:54, Bernhard Übelacker wrote:
>> Am 31.01.22 um 16:24 schrieb Rémi Bernon:
>>> MK11 creates an alternate stack and sometimes throws an exception which
>>> gets incorrectly handled by a Wine exception handler, causing the game
>>> to crash.
>>>
>>> Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
>>> ---
>>>   dlls/ntdll/signal_x86_64.c | 4 +++-
>>>   1 file changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
>>> index 7e77329363c..36985832e4a 100644
>>> --- a/dlls/ntdll/signal_x86_64.c
>>> +++ b/dlls/ntdll/signal_x86_64.c
>>> @@ -463,7 +463,9 @@ static NTSTATUS call_stack_handlers( 
>>> EXCEPTION_RECORD *rec, CONTEXT *orig_contex
>>>               }
>>>           }
>>>           /* hack: call wine handlers registered in the tib list */
>>> -        else while ((ULONG64)teb_frame < context.Rsp)
>>> +        else while ((ULONG64)teb_frame < context.Rsp &&
>>> +                    (ULONG64)teb_frame >= 
>>> (ULONG64)NtCurrentTeb()->Tib.StackLimit &&
>>> +                    (ULONG64)teb_frame <= 
>>> (ULONG64)NtCurrentTeb()->Tib.StackBase)
>>>           {
>>>               TRACE_(seh)( "found wine frame %p rsp %p handler %p\n",
>>>                            teb_frame, (void *)context.Rsp, 
>>> teb_frame->Handler );
>>
>> I am not sure but this seems kind of similar to what I think I found in
>> this bug: https://bugs.winehq.org/show_bug.cgi?id=52159
>>
> Yes, that looks quite similar. All these fix attempts workaround the 
> problem where it is first visibly hit (calling wrong handler) but ignore 
> what may happen to these handlers after. What if the app, e. g., 
> switches stack back? And RtlUnwindEx()?
> 
> Actually the majority of Wine __TRY blocks should have rather low 
> chances to hit app's stack switch in between the handler is installed 
> and removed (unless the app is doing something really fun with 
> hotpatching). Those IsBad..Ptr(), a bunch of cases when the parameter 
> access is wrapped into __TRY, OutputDebugString() are not much likely to 
> hit such an issue. There are relatively few __TRY blocks which embrace 
> application functions: calling thread func, calling DLL entry points, 
> exception handlers calls in signal_x86_64.c (and maybe I missed some). 
> Since you probably hit the issue with Proton that is not the nested 
> exception handlers as those in Proton already have manual asm wrappers 
> to use straightforward x64 .seh handling and don't install Teb handlers. 
> If maybe there are just one or two of other "global" handlers which are 
> problematic maybe it worth solving the issue with some sort of manual 
> .seh specifically for those ones?
> 

In the case of MK11, the wine handler is the one installed by 
RtlUserThreadStart.

I don't see anywhere any clue about how the thread is switching stacks, 
it just happens to use alternate stacks after a while, and has actually 
quite a few different stacks, probably re-implementing its own fibers 
(it doesn't call SwitchToFiber).

When they switch stacks they don't change the ExceptionList pointer 
though (probably as I understand it because it's not supposed to be used 
on Win64), so it's always ultimately pointing to the initial handler on 
the initial stack.

There's then still quite a lot of Wine exception handlers being pushed / 
poped (IsBadString, C++ dynamic casts, etc...), though they don't 
usually callback any user code.

-- 
Rémi Bernon <rbernon at codeweavers.com>



More information about the wine-devel mailing list