The frame can currently be reset from ws2_32.dll async IO callbacks which are still in the user part and are calling 'syscall' functions. If the user APC is processed after that during the same call to server_select(), the call_user_apc_dispatcher() faults.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49782 Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/unix/server.c | 16 ++++++++++++++++ dlls/ntdll/unix/signal_arm.c | 9 +++++++++ dlls/ntdll/unix/signal_arm64.c | 10 ++++++++++ dlls/ntdll/unix/signal_i386.c | 10 ++++++++++ dlls/ntdll/unix/signal_x86_64.c | 9 +++++++++ dlls/ntdll/unix/unix_private.h | 3 +++ 6 files changed, 57 insertions(+)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 87dd4b10b83..a9608abfb73 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -389,8 +389,24 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result ) { IO_STATUS_BLOCK *iosb = wine_server_get_ptr( call->async_io.sb ); NTSTATUS (**user)(void *, IO_STATUS_BLOCK *, NTSTATUS) = wine_server_get_ptr( call->async_io.user ); + void *saved_frame = get_syscall_frame(); + void *frame; + result->type = call->type; result->async_io.status = (*user)( user, iosb, call->async_io.status ); + + if ((frame = get_syscall_frame()) != saved_frame) + { + /* The frame can be altered by syscalls from ws2_32 async callbacks + * which are currently in the user part. */ + static unsigned int once; + + if (!once++) + FIXME( "syscall frame changed in APC function, frame %p, saved_frame %p.\n", frame, saved_frame ); + + set_syscall_frame( saved_frame ); + } + if (result->async_io.status != STATUS_PENDING) result->async_io.total = iosb->Information; break; diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index e8971d22dbd..487c8501cc7 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -203,6 +203,15 @@ static inline struct arm_thread_data *arm_thread_data(void) return (struct arm_thread_data *)ntdll_get_thread_data()->cpu_data; }
+void *get_syscall_frame(void) +{ + return arm_thread_data()->syscall_frame; +} + +void set_syscall_frame(void *frame) +{ + arm_thread_data()->syscall_frame = frame; +}
/*********************************************************************** * unwind_builtin_dll diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 3beef729dca..95042de45e1 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -157,6 +157,16 @@ static inline struct arm64_thread_data *arm64_thread_data(void) return (struct arm64_thread_data *)ntdll_get_thread_data()->cpu_data; }
+void *get_syscall_frame(void) +{ + return arm64_thread_data()->syscall_frame; +} + +void set_syscall_frame(void *frame) +{ + arm64_thread_data()->syscall_frame = frame; +} + extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher );
/*********************************************************************** diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index c8690b51f2f..ff9d8a12c14 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -495,6 +495,16 @@ static inline struct x86_thread_data *x86_thread_data(void) return (struct x86_thread_data *)ntdll_get_thread_data()->cpu_data; }
+void *get_syscall_frame(void) +{ + return x86_thread_data()->syscall_frame; +} + +void set_syscall_frame(void *frame) +{ + x86_thread_data()->syscall_frame = frame; +} + static inline WORD get_cs(void) { WORD res; __asm__( "movw %%cs,%0" : "=r" (res) ); return res; } static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; } static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 837cd9ed654..1fd26d5bd76 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -306,6 +306,15 @@ static inline struct amd64_thread_data *amd64_thread_data(void) return (struct amd64_thread_data *)ntdll_get_thread_data()->cpu_data; }
+void *get_syscall_frame(void) +{ + return amd64_thread_data()->syscall_frame; +} + +void set_syscall_frame(void *frame) +{ + amd64_thread_data()->syscall_frame = frame; +}
/*********************************************************************** * Definitions for Dwarf unwind tables diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 23731f0fdc6..f8f50d0ab27 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -247,6 +247,9 @@ extern void WINAPI DECLSPEC_NORETURN call_user_exception_dispatcher( EXCEPTION_R NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) DECLSPEC_HIDDEN; extern void WINAPI DECLSPEC_NORETURN call_raise_user_exception_dispatcher( NTSTATUS (WINAPI *dispatcher)(void) ) DECLSPEC_HIDDEN;
+extern void *get_syscall_frame(void) DECLSPEC_HIDDEN; +extern void set_syscall_frame(void *frame) DECLSPEC_HIDDEN; + #define TICKSPERSEC 10000000 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400)