Follow up to https://gitlab.winehq.org/wine/wine/-/merge_requests/9209#note_120396
-- v3: ucrtbase: Add __C_specific_handler tests.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vcruntime140/Makefile.in | 6 +- dlls/vcruntime140/signal_arm.c | 34 ++++ dlls/vcruntime140/signal_arm64.c | 54 ++++++ dlls/vcruntime140/signal_arm64ec.c | 57 ++++++ dlls/vcruntime140/unwind.c | 284 ++++++++++++++++++++++++++++ dlls/vcruntime140/vcruntime140.spec | 2 +- 6 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 dlls/vcruntime140/signal_arm.c create mode 100644 dlls/vcruntime140/signal_arm64.c create mode 100644 dlls/vcruntime140/signal_arm64ec.c create mode 100644 dlls/vcruntime140/unwind.c
diff --git a/dlls/vcruntime140/Makefile.in b/dlls/vcruntime140/Makefile.in index 1f99225ffe8..3fffd0e25b6 100644 --- a/dlls/vcruntime140/Makefile.in +++ b/dlls/vcruntime140/Makefile.in @@ -2,4 +2,8 @@ MODULE = vcruntime140.dll IMPORTLIB = vcruntime140
SOURCES = \ - misc.c + misc.c \ + signal_arm64.c \ + signal_arm.c \ + signal_arm64ec.c \ + unwind.c diff --git a/dlls/vcruntime140/signal_arm.c b/dlls/vcruntime140/signal_arm.c new file mode 100644 index 00000000000..aca6a8b4697 --- /dev/null +++ b/dlls/vcruntime140/signal_arm.c @@ -0,0 +1,34 @@ +/* + * ARM signal handling routines + * + * Copyright 2002 Marcus Meissner, SuSE Linux AG + * Copyright 2010-2013, 2015 André Hentschel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __arm__ + +#include <wine/asm.h> + +__ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter, + "push {r3-r11,lr}\n\t" + ".seh_save_regs_w {r3-r11,lr}\n\t" + ".seh_endprologue\n\t" + "ldm r3, {r4-r11}\n\t" + "blx r2\n\t" + "pop {r3-r11,pc}\n\t" ); + +#endif diff --git a/dlls/vcruntime140/signal_arm64.c b/dlls/vcruntime140/signal_arm64.c new file mode 100644 index 00000000000..e1aa3965cc3 --- /dev/null +++ b/dlls/vcruntime140/signal_arm64.c @@ -0,0 +1,54 @@ +/* + * ARM64 signal handling routines + * + * Copyright 2010-2013 André Hentschel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __aarch64__ + +#include "wine/asm.h" + +__ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter, + "stp x29, x30, [sp, #-96]!\n\t" + ".seh_save_fplr_x 96\n\t" + "stp x19, x20, [sp, #16]\n\t" + ".seh_save_regp x19, 16\n\t" + "stp x21, x22, [sp, #32]\n\t" + ".seh_save_regp x21, 32\n\t" + "stp x23, x24, [sp, #48]\n\t" + ".seh_save_regp x23, 48\n\t" + "stp x25, x26, [sp, #64]\n\t" + ".seh_save_regp x25, 64\n\t" + "stp x27, x28, [sp, #80]\n\t" + ".seh_save_regp x27, 80\n\t" + ".seh_endprologue\n\t" + "ldp x19, x20, [x3, #0]\n\t" /* nonvolatile regs */ + "ldp x21, x22, [x3, #16]\n\t" + "ldp x23, x24, [x3, #32]\n\t" + "ldp x25, x26, [x3, #48]\n\t" + "ldp x27, x28, [x3, #64]\n\t" + "ldr x1, [x3, #80]\n\t" /* x29 = frame */ + "blr x2\n\t" /* filter */ + "ldp x19, x20, [sp, #16]\n\t" + "ldp x21, x22, [sp, #32]\n\t" + "ldp x23, x24, [sp, #48]\n\t" + "ldp x25, x26, [sp, #64]\n\t" + "ldp x27, x28, [sp, #80]\n\t" + "ldp x29, x30, [sp], #96\n\t" + "ret"); + +#endif diff --git a/dlls/vcruntime140/signal_arm64ec.c b/dlls/vcruntime140/signal_arm64ec.c new file mode 100644 index 00000000000..3ff6169699e --- /dev/null +++ b/dlls/vcruntime140/signal_arm64ec.c @@ -0,0 +1,57 @@ +/* + * ARM64EC signal handling routines + * + * Copyright 1999, 2005, 2023 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __arm64ec__ + +#include <windef.h> + +#include <wine/asm.h> + +LONG __attribute__((naked)) __C_ExecuteExceptionFilter( EXCEPTION_POINTERS *ptrs, void *frame, + PEXCEPTION_FILTER filter, BYTE *nonvolatile ) +{ + asm( ".seh_proc _C_ExecuteExceptionFilter\n\t" + "stp x29, x30, [sp, #-80]!\n\t" + ".seh_save_fplr_x 80\n\t" + "stp x19, x20, [sp, #16]\n\t" + ".seh_save_regp x19, 16\n\t" + "stp x21, x22, [sp, #32]\n\t" + ".seh_save_regp x21, 32\n\t" + "stp x25, x26, [sp, #48]\n\t" + ".seh_save_regp x25, 48\n\t" + "str x27, [sp, #64]\n\t" + ".seh_save_reg x27, 64\n\t" + ".seh_endprologue\n\t" + "ldp x19, x20, [x3, #0]\n\t" /* nonvolatile regs */ + "ldp x21, x22, [x3, #16]\n\t" + "ldp x25, x26, [x3, #48]\n\t" + "ldr x27, [x3, #64]\n\t" + "ldr x1, [x3, #80]\n\t" /* x29 = frame */ + "blr x2\n\t" /* filter */ + "ldp x19, x20, [sp, #16]\n\t" + "ldp x21, x22, [sp, #32]\n\t" + "ldp x25, x26, [sp, #48]\n\t" + "ldr x27, [sp, #64]\n\t" + "ldp x29, x30, [sp], #80\n\t" + "ret\n\t" + ".seh_endproc" ); +} + +#endif diff --git a/dlls/vcruntime140/unwind.c b/dlls/vcruntime140/unwind.c new file mode 100644 index 00000000000..c847cee5d46 --- /dev/null +++ b/dlls/vcruntime140/unwind.c @@ -0,0 +1,284 @@ +/* + * Exception unwinding + * + * Copyright 1999, 2005, 2019, 2024 Alexandre Julliard + * Copyright 2021 Martin Storsjö + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include <ntstatus.h> +#define WIN32_NO_STATUS +#include <windef.h> +#include <winternl.h> + +#include <wine/exception.h> +#include <wine/debug.h> + +#ifndef __i386__ + +WINE_DEFAULT_DEBUG_CHANNEL(vcruntime140); +WINE_DECLARE_DEBUG_CHANNEL(unwind); + +#define DUMP_SCOPE_TABLE(base,table) do { \ + for (unsigned int i = 0; i < table->Count; i++) \ + TRACE( " %u: %p-%p handler %p target %p\n", i, \ + (char *)base + table->ScopeRecord[i].BeginAddress, \ + (char *)base + table->ScopeRecord[i].EndAddress, \ + (char *)base + table->ScopeRecord[i].HandlerAddress, \ + (char *)base + table->ScopeRecord[i].JumpTarget ); \ +} while(0) + +#define CXX_EXCEPTION 0xe06d7363 + +extern LONG __C_ExecuteExceptionFilter( EXCEPTION_POINTERS *ptrs, void *frame, PEXCEPTION_FILTER filter, + BYTE *nonvolatile ); + +extern void CDECL __DestructExceptionObject( EXCEPTION_RECORD *rec ); + +/* The __C_specific_handler in vcruntime calls the destructor for the exception object if: + * The current exception is a C++ exception. + * A matching SEH handler was found. + */ + +#if defined(__aarch64__) || defined(__arm64ec__) +#ifdef __arm64ec__ +#define __C_specific_handler __C_specific_handler_arm64 +#endif + +EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec, void *frame, + ARM64_NT_CONTEXT *context, + DISPATCHER_CONTEXT_ARM64 *dispatch ) +{ + const SCOPE_TABLE *table = dispatch->HandlerData; + ULONG_PTR base = dispatch->ImageBase; + ULONG_PTR pc = dispatch->ControlPc; + unsigned int i; + void *handler; + + TRACE( "%p %p %p %p pc %Ix\n", rec, frame, context, dispatch, pc ); + if (TRACE_ON(unwind)) DUMP_SCOPE_TABLE( base, table ); + + if (dispatch->ControlPcIsUnwound) pc -= 4; + + if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (table->ScopeRecord[i].JumpTarget) continue; + + if (rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND && + dispatch->TargetPc >= base + table->ScopeRecord[i].BeginAddress && + dispatch->TargetPc < base + table->ScopeRecord[i].EndAddress) + { + break; + } + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + dispatch->ScopeIndex = i + 1; + TRACE( "scope %u calling __finally %p frame %p\n", i, handler, frame ); + __C_ExecuteExceptionFilter( ULongToPtr(TRUE), frame, handler, dispatch->NonVolatileRegisters ); + } + } + else + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (!table->ScopeRecord[i].JumpTarget) continue; + + if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER) + { + EXCEPTION_POINTERS ptrs = { rec, (CONTEXT *)context }; + + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + TRACE( "scope %u calling filter %p ptrs %p frame %p\n", i, handler, &ptrs, frame ); + switch (__C_ExecuteExceptionFilter( &ptrs, frame, handler, dispatch->NonVolatileRegisters )) + { + case EXCEPTION_EXECUTE_HANDLER: + break; + case EXCEPTION_CONTINUE_SEARCH: + continue; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + } + } + if (rec->ExceptionCode == CXX_EXCEPTION) __DestructExceptionObject( rec ); + + TRACE( "unwinding to target %Ix\n", base + table->ScopeRecord[i].JumpTarget ); + RtlUnwindEx( frame, (char *)base + table->ScopeRecord[i].JumpTarget, + rec, ULongToPtr(rec->ExceptionCode), (CONTEXT *)dispatch->ContextRecord, + dispatch->HistoryTable ); + } + } + return ExceptionContinueSearch; +} +#ifdef __arm64ec__ +#undef __C_specific_handler +#endif +#endif /* __aarch64__ || __arm64ec__ */ + +#ifdef __arm__ +EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec, void *frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) +{ + const SCOPE_TABLE *table = dispatch->HandlerData; + ULONG_PTR base = dispatch->ImageBase; + ULONG_PTR pc = dispatch->ControlPc; + unsigned int i; + void *handler; + + TRACE( "%p %p %p %p pc %Ix\n", rec, frame, context, dispatch, pc ); + if (TRACE_ON(unwind)) DUMP_SCOPE_TABLE( base, table ); + + if (dispatch->ControlPcIsUnwound) pc -= 2; + + if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (table->ScopeRecord[i].JumpTarget) continue; + + if (rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND && + dispatch->TargetPc >= base + table->ScopeRecord[i].BeginAddress && + dispatch->TargetPc < base + table->ScopeRecord[i].EndAddress) + { + break; + } + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + dispatch->ScopeIndex = i + 1; + TRACE( "scope %u calling __finally %p frame %p\n", i, handler, frame ); + __C_ExecuteExceptionFilter( ULongToPtr(TRUE), frame, handler, dispatch->NonVolatileRegisters ); + } + } + else + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (!table->ScopeRecord[i].JumpTarget) continue; + + if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER) + { + EXCEPTION_POINTERS ptrs = { rec, context }; + + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + TRACE( "scope %u calling filter %p ptrs %p frame %p\n", i, handler, &ptrs, frame ); + switch (__C_ExecuteExceptionFilter( &ptrs, frame, handler, dispatch->NonVolatileRegisters )) + { + case EXCEPTION_EXECUTE_HANDLER: + break; + case EXCEPTION_CONTINUE_SEARCH: + continue; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + } + } + if (rec->ExceptionCode == CXX_EXCEPTION) __DestructExceptionObject( rec ); + + TRACE( "unwinding to target %lx\n", base + table->ScopeRecord[i].JumpTarget ); + RtlUnwindEx( frame, (char *)base + table->ScopeRecord[i].JumpTarget, + rec, ULongToPtr(rec->ExceptionCode), dispatch->ContextRecord, + dispatch->HistoryTable ); + } + } + return ExceptionContinueSearch; +} +#endif /* __arm__ */ + +#ifdef __x86_64__ +EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec, void *frame, CONTEXT *context, + DISPATCHER_CONTEXT *dispatch ) +{ + const SCOPE_TABLE *table = dispatch->HandlerData; + ULONG_PTR base = dispatch->ImageBase; + ULONG_PTR pc = dispatch->ControlPc; + unsigned int i; + +#ifdef __arm64ec__ + if (RtlIsEcCode( pc )) + return __C_specific_handler_arm64( rec, frame, (ARM64_NT_CONTEXT *)context, + (DISPATCHER_CONTEXT_ARM64 *)dispatch ); +#endif + + TRACE( "%p %p %p %p pc %Ix\n", rec, frame, context, dispatch, pc ); + if (TRACE_ON(unwind)) DUMP_SCOPE_TABLE( base, table ); + + if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (table->ScopeRecord[i].JumpTarget) continue; + + if (rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND && + dispatch->TargetIp >= base + table->ScopeRecord[i].BeginAddress && + dispatch->TargetIp < base + table->ScopeRecord[i].EndAddress) + { + break; + } + else + { + PTERMINATION_HANDLER handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + dispatch->ScopeIndex = i + 1; + TRACE( "scope %u calling __finally %p frame %p\n", i, handler, frame ); + handler( TRUE, frame ); + } + } + } + else + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (!table->ScopeRecord[i].JumpTarget) continue; + + if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER) + { + EXCEPTION_POINTERS ptrs = { rec, context }; + PEXCEPTION_FILTER filter = (void *)(base + table->ScopeRecord[i].HandlerAddress); + + TRACE( "scope %u calling filter %p ptrs %p frame %p\n", i, filter, &ptrs, frame ); + switch (filter( &ptrs, frame )) + { + case EXCEPTION_EXECUTE_HANDLER: + break; + case EXCEPTION_CONTINUE_SEARCH: + continue; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + } + } + if (rec->ExceptionCode == CXX_EXCEPTION) __DestructExceptionObject( rec ); + + TRACE( "unwinding to target %Ix\n", base + table->ScopeRecord[i].JumpTarget ); + RtlUnwindEx( frame, (char *)base + table->ScopeRecord[i].JumpTarget, + rec, ULongToPtr(rec->ExceptionCode), dispatch->ContextRecord, + dispatch->HistoryTable ); + } + } + return ExceptionContinueSearch; +} +#endif /* __x86_64__ */ +#endif /* !i386 */ \ No newline at end of file diff --git a/dlls/vcruntime140/vcruntime140.spec b/dlls/vcruntime140/vcruntime140.spec index 6a04f162b54..d4587f9ba1f 100644 --- a/dlls/vcruntime140/vcruntime140.spec +++ b/dlls/vcruntime140/vcruntime140.spec @@ -10,7 +10,7 @@ @ cdecl __AdjustPointer(ptr ptr) ucrtbase.__AdjustPointer @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) @ stub __C_specific_handler_noexcept @ cdecl __CxxDetectRethrow(ptr) ucrtbase.__CxxDetectRethrow @ cdecl __CxxExceptionFilter(ptr ptr long ptr) ucrtbase.__CxxExceptionFilter
From: Vibhav Pant vibhavp@gmail.com
--- dlls/msvcp90/exception.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/dlls/msvcp90/exception.c b/dlls/msvcp90/exception.c index aef1268068c..df2f52c0755 100644 --- a/dlls/msvcp90/exception.c +++ b/dlls/msvcp90/exception.c @@ -43,7 +43,7 @@ CREATE_TYPE_INFO_VTABLE
#define CLASS_IS_SIMPLE_TYPE 1 #define CLASS_HAS_VIRTUAL_BASE_CLASS 4 -#define CLASS_IS_IUNKNOWN 8 +#define CLASS_IS_WINRT 8
int* __cdecl __processing_throw(void);
@@ -1200,8 +1200,10 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, { if (type->flags & CLASS_IS_SIMPLE_TYPE) { - if (type->flags & CLASS_IS_IUNKNOWN && *(IUnknown**)object) - IUnknown_AddRef(*(IUnknown**)object); + /* WinRT exceptions are thrown with a reference count of 2, the refcount is decreased before it's handed off to a + * matching catch block. */ + if (type->flags & CLASS_IS_WINRT && *(IUnknown**)object) + IUnknown_Release(*(IUnknown**)object); memmove( dest, object, type->size ); /* if it is a pointer, adjust it */ if (type->size == sizeof(void*)) *dest = get_this_pointer( &type->offsets, *dest ); @@ -1216,8 +1218,8 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, } else { - if (type->flags & CLASS_IS_IUNKNOWN && *(IUnknown**)object) - IUnknown_AddRef(*(IUnknown**)object); + if (type->flags & CLASS_IS_WINRT && *(IUnknown**)object) + IUnknown_Release(*(IUnknown**)object); memmove( dest, get_this_pointer( &type->offsets, object ), type->size ); } }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/msvcrt/cppexcept.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcrt/cppexcept.h b/dlls/msvcrt/cppexcept.h index 0f64f97dd20..9abdcc0569b 100644 --- a/dlls/msvcrt/cppexcept.h +++ b/dlls/msvcrt/cppexcept.h @@ -261,8 +261,10 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, } else if (type->flags & CLASS_IS_SIMPLE_TYPE) { + /* WinRT exceptions are thrown with a reference count of 2, the refcount is decreased before it's handed off to a + * matching catch block. */ if (type->flags & CLASS_IS_WINRT && *(IUnknown**)object) - IUnknown_AddRef(*(IUnknown**)object); + IUnknown_Release(*(IUnknown**)object); memmove( dest, object, type->size ); /* if it is a pointer, adjust it */ if (type->size == sizeof(void*)) *dest = get_this_pointer( &type->offsets, *dest ); @@ -278,7 +280,7 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, else { if (type->flags & CLASS_IS_WINRT && *(IUnknown**)object) - IUnknown_AddRef(*(IUnknown**)object); + IUnknown_Release(*(IUnknown**)object); memmove( dest, get_this_pointer( &type->offsets, object ), type->size ); } }
From: Piotr Caban piotr@codeweavers.com
--- dlls/ucrtbase/tests/cpp.c | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+)
diff --git a/dlls/ucrtbase/tests/cpp.c b/dlls/ucrtbase/tests/cpp.c index da06b2cbf2f..e5b52872cd6 100644 --- a/dlls/ucrtbase/tests/cpp.c +++ b/dlls/ucrtbase/tests/cpp.c @@ -24,6 +24,8 @@
#include <windef.h> #include <winbase.h> +#include <winternl.h> +#include <rtlsupportapi.h> #include <verrsrc.h> #include <dbghelp.h> #include <unknwn.h> @@ -323,6 +325,84 @@ static void test___DestructExceptionObject(void) CHECK_CALLED(iunknown_except_Release); }
+#ifdef __x86_64__ +EXCEPTION_DISPOSITION WINAPI __C_specific_handler(EXCEPTION_RECORD*,void*,CONTEXT*,DISPATCHER_CONTEXT*); +DEFINE_EXPECT(filter); +static CONTEXT ctx; + +static ULONG WINAPI iunknown_except2_Release(IUnknown *iface) +{ + CHECK_EXPECT(iunknown_except_Release); + NtContinue(&ctx, FALSE); + return 1; +} + +static IUnknownVtbl iunknown_except2_vtbl = { + iunknown_except_QueryInterface, + iunknown_except_AddRef, + iunknown_except2_Release +}; + +static IUnknown iunknown_except2 = { &iunknown_except2_vtbl }; + +static LONG WINAPI filter(struct _EXCEPTION_POINTERS *ep, void *frame) +{ + CHECK_EXPECT(filter); + + ok(frame == (void*)0x1234, "frame = %p\n", (void*)frame); + SET_EXPECT(iunknown_except_Release); + return EXCEPTION_EXECUTE_HANDLER; +} + +static void test___C_specific_handler(void) +{ + struct + { + UINT flags; + UINT arch_specific_data[8]; + } info = { 0x10 }; + IUnknown *piunk = &iunknown_except2; + DISPATCHER_CONTEXT dispatch; + SCOPE_TABLE scope_table; + EXCEPTION_RECORD rec; + CONTEXT context; + LONG pass = 0; + + InterlockedIncrement(&pass); + RtlCaptureContext(&ctx); + if (InterlockedIncrement(&pass) == 3) + { + CHECK_CALLED(filter); + CHECK_CALLED(iunknown_except_Release); + return; + } + + memset(&rec, 0, sizeof(rec)); + rec.ExceptionCode = 0xe06d7363; + rec.NumberParameters = 4; + rec.ExceptionInformation[0] = 0x19930520; + rec.ExceptionInformation[1] = (ULONG_PTR)&piunk; + rec.ExceptionInformation[2] = (ULONG_PTR)&info; + rec.ExceptionInformation[3] = (ULONG_PTR)GetModuleHandleA(NULL); + + memset(&dispatch, 0, sizeof(dispatch)); + dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL); + dispatch.ControlPc = dispatch.ImageBase + 0x200; + dispatch.HandlerData = &scope_table; + dispatch.ContextRecord = &context; + scope_table.Count = 1; + scope_table.ScopeRecord[0].BeginAddress = 0x200; + scope_table.ScopeRecord[0].EndAddress = 0x400; + scope_table.ScopeRecord[0].HandlerAddress = (ULONG_PTR)filter - dispatch.ImageBase; + scope_table.ScopeRecord[0].JumpTarget = 1; + memset(&context, 0, sizeof(context)); + + SET_EXPECT(filter); + __C_specific_handler(&rec, (void*)0x1234, &context, &dispatch); + ok(0, "should not be reached\n"); +} +#endif + START_TEST(cpp) { if (!init()) return; @@ -330,4 +410,7 @@ START_TEST(cpp) test___std_type_info(); test___unDName(); test___DestructExceptionObject(); +#ifdef __x86_64__ + test___C_specific_handler(); +#endif }
I've added a test for __C_specific_hanlder change (I have also confirmed that ntdll version works differently in that case).