[PATCH 0/4] MR9285: msvcrt: Improvements for WinRT exceptions
It's a dependency of !9209. I'm not sure yet if more changes are needed on ucrtbase/msvcp140 side. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9285
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msvcp90/exception.c | 47 ++++++++++++++++++------------------- dlls/msvcrt/exception_ptr.c | 26 ++------------------ 2 files changed, 25 insertions(+), 48 deletions(-) diff --git a/dlls/msvcp90/exception.c b/dlls/msvcp90/exception.c index c78d40bfce7..daa0cdf72bc 100644 --- a/dlls/msvcp90/exception.c +++ b/dlls/msvcp90/exception.c @@ -1199,6 +1199,27 @@ static inline void call_dtor( void *func, void *this ) } #endif +/* copy the exception object where the catch block wants it */ +static inline void copy_exception( void *object, void **dest, UINT catch_flags, + const cxx_type_info *type, uintptr_t base ) +{ + if (type->flags & CLASS_IS_SIMPLE_TYPE) + { + memmove( dest, object, type->size ); + /* if it is a pointer, adjust it */ + if (type->size == sizeof(void*)) *dest = get_this_pointer( &type->offsets, *dest ); + } + else /* copy the object */ + { + if (type->copy_ctor) + call_copy_ctor( cxx_rva( type->copy_ctor, base ), dest, + get_this_pointer( &type->offsets, object ), + (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) ); + else + memmove( dest, get_this_pointer( &type->offsets, object ), type->size ); + } +} + int __cdecl __uncaught_exceptions(void) { return *__processing_throw(); @@ -1317,18 +1338,7 @@ void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) const cxx_type_info *ti = cxx_rva( table->info[0], base ); void **data = HeapAlloc(GetProcessHeap(), 0, ti->size); - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, obj, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor(cxx_rva(ti->copy_ctor, base), data, get_this_pointer(&ti->offsets, obj), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size); + copy_exception(obj, data, 0, ti, base); ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; } return; @@ -1372,18 +1382,7 @@ void __cdecl __ExceptionPtrCopyException(exception_ptr *ep, table = cxx_rva( type->type_info_table, base ); ti = cxx_rva( table->info[0], base ); data = HeapAlloc(GetProcessHeap(), 0, ti->size); - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, object, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor( cxx_rva(ti->copy_ctor, base), data, get_this_pointer(&ti->offsets, object), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS ); - } - else - memcpy(data, get_this_pointer(&ti->offsets, object), ti->size); + copy_exception(object, data, 0, ti, base); ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; } diff --git a/dlls/msvcrt/exception_ptr.c b/dlls/msvcrt/exception_ptr.c index 6e2216695a8..dd2c6b0ac5c 100644 --- a/dlls/msvcrt/exception_ptr.c +++ b/dlls/msvcrt/exception_ptr.c @@ -173,18 +173,7 @@ void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec) const cxx_type_info *ti = cxx_rva( table->info[0], base ); void **data = HeapAlloc(GetProcessHeap(), 0, ti->size); - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, obj, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor(cxx_rva(ti->copy_ctor, base), data, get_this_pointer(&ti->offsets, obj), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size); + copy_exception(obj, data, 0, ti, base); ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; } return; @@ -242,18 +231,7 @@ void __cdecl __ExceptionPtrCopyException(exception_ptr *ep, table = cxx_rva( type->type_info_table, base ); ti = cxx_rva( table->info[0], base ); data = HeapAlloc(GetProcessHeap(), 0, ti->size); - if (ti->flags & CLASS_IS_SIMPLE_TYPE) - { - memcpy(data, object, ti->size); - if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data); - } - else if (ti->copy_ctor) - { - call_copy_ctor( cxx_rva(ti->copy_ctor, base), data, get_this_pointer(&ti->offsets, object), - ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS); - } - else - memcpy(data, get_this_pointer(&ti->offsets, object), ti->size); + copy_exception(object, data, 0, ti, base); ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9285
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msvcrt/cppexcept.h | 1 + dlls/msvcrt/except.c | 20 +++++---- dlls/ucrtbase/tests/cpp.c | 85 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/dlls/msvcrt/cppexcept.h b/dlls/msvcrt/cppexcept.h index 3070884000f..2bd2e2f9c62 100644 --- a/dlls/msvcrt/cppexcept.h +++ b/dlls/msvcrt/cppexcept.h @@ -136,6 +136,7 @@ typedef struct #define TYPE_FLAG_CONST 1 #define TYPE_FLAG_VOLATILE 2 #define TYPE_FLAG_REFERENCE 8 +#define TYPE_FLAG_IUNKNOWN 16 void WINAPI DECLSPEC_NORETURN _CxxThrowException(void*,const cxx_exception_type*); diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c index cdb9a58822d..bed1df0276e 100644 --- a/dlls/msvcrt/except.c +++ b/dlls/msvcrt/except.c @@ -26,6 +26,8 @@ #include <stdarg.h> #include <stdbool.h> +#define COBJMACROS + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -33,6 +35,7 @@ #include "winternl.h" #include "msvcrt.h" #include "excpt.h" +#include "unknwn.h" #include "wincon.h" #include "wine/exception.h" #include "wine/debug.h" @@ -949,17 +952,20 @@ BOOL __cdecl _IsExceptionObjectToBeDestroyed(const void *obj) */ void CDECL __DestructExceptionObject(EXCEPTION_RECORD *rec) { - cxx_exception_type *info = (cxx_exception_type*) rec->ExceptionInformation[2]; - void *object = (void*)rec->ExceptionInformation[1]; + cxx_exception_type *info; + void *object; TRACE("(%p)\n", rec); - if (!is_cxx_exception( rec )) return; - - if (!info || !info->destructor) - return; + if (!rec || !is_cxx_exception( rec )) return; + info = (cxx_exception_type*)rec->ExceptionInformation[2]; + if (!info) return; + object = (void*)rec->ExceptionInformation[1]; - call_dtor( cxx_rva( info->destructor, rec->ExceptionInformation[3] ), object ); + if (info->destructor) + call_dtor( cxx_rva( info->destructor, rec->ExceptionInformation[3] ), object ); + else if (info->flags & TYPE_FLAG_IUNKNOWN && *(IUnknown**)object) + IUnknown_Release( *(IUnknown**)object ); } /********************************************************************* diff --git a/dlls/ucrtbase/tests/cpp.c b/dlls/ucrtbase/tests/cpp.c index 5e62aafa1a8..da06b2cbf2f 100644 --- a/dlls/ucrtbase/tests/cpp.c +++ b/dlls/ucrtbase/tests/cpp.c @@ -26,8 +26,35 @@ #include <winbase.h> #include <verrsrc.h> #include <dbghelp.h> +#include <unknwn.h> #include "wine/test.h" +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(iunknown_except_Release); + typedef unsigned char MSVCRT_bool; typedef struct { @@ -47,6 +74,8 @@ typedef struct _type_info_list char name[1]; } type_info_list; +void CDECL __DestructExceptionObject(EXCEPTION_RECORD*); + static void* (CDECL *p_malloc)(size_t); static void (CDECL *p___std_exception_copy)(const __std_exception_data*, __std_exception_data*); static void (CDECL *p___std_exception_destroy)(__std_exception_data*); @@ -239,10 +268,66 @@ static void test___unDName(void) } } +static HRESULT WINAPI iunknown_except_QueryInterface(IUnknown *iface, + REFIID riid, void**ppv) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI iunknown_except_AddRef(IUnknown *iface) +{ + ok(0, "unexpected call\n"); + return 2; +} + +static ULONG WINAPI iunknown_except_Release(IUnknown *iface) +{ + CHECK_EXPECT(iunknown_except_Release); + return 1; +} + +static IUnknownVtbl iunknown_except_vtbl = { + iunknown_except_QueryInterface, + iunknown_except_AddRef, + iunknown_except_Release +}; + +static IUnknown iunknown_except = { &iunknown_except_vtbl }; + +static void test___DestructExceptionObject(void) +{ + IUnknown *piunk = &iunknown_except; + EXCEPTION_RECORD rec; + struct + { + UINT flags; + UINT arch_specific_data[8]; + } info = { 0x10 }; + + __DestructExceptionObject(NULL); + + memset(&rec, 0, sizeof(rec)); + rec.ExceptionCode = 0xe06d7363; +#ifdef __i386__ + rec.NumberParameters = 3; +#else + rec.NumberParameters = 4; +#endif + rec.ExceptionInformation[0] = 0x19930520; + rec.ExceptionInformation[1] = (ULONG_PTR)&piunk; + rec.ExceptionInformation[2] = (ULONG_PTR)&info; + rec.ExceptionInformation[3] = (ULONG_PTR)GetModuleHandleA(NULL); + SET_EXPECT(iunknown_except_Release); + __DestructExceptionObject(&rec); + CHECK_CALLED(iunknown_except_Release); +} + START_TEST(cpp) { if (!init()) return; test___std_exception(); test___std_type_info(); test___unDName(); + test___DestructExceptionObject(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9285
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msvcp90/exception.c | 12 ++++++++++++ dlls/msvcrt/cppexcept.h | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/dlls/msvcp90/exception.c b/dlls/msvcp90/exception.c index daa0cdf72bc..015d6e85da6 100644 --- a/dlls/msvcp90/exception.c +++ b/dlls/msvcp90/exception.c @@ -19,11 +19,14 @@ #include <errno.h> #include <stdarg.h> +#define COBJMACROS + #include "msvcp90.h" #include "windef.h" #include "winbase.h" #include "winternl.h" #include "rtlsupportapi.h" +#include "unknwn.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msvcp); @@ -40,6 +43,7 @@ CREATE_TYPE_INFO_VTABLE #define CLASS_IS_SIMPLE_TYPE 1 #define CLASS_HAS_VIRTUAL_BASE_CLASS 4 +#define CLASS_IS_IUNKNOWN 8 int* __cdecl __processing_throw(void); @@ -1205,6 +1209,8 @@ 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); memmove( dest, object, type->size ); /* if it is a pointer, adjust it */ if (type->size == sizeof(void*)) *dest = get_this_pointer( &type->offsets, *dest ); @@ -1212,11 +1218,17 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, else /* copy the object */ { if (type->copy_ctor) + { call_copy_ctor( cxx_rva( type->copy_ctor, base ), dest, get_this_pointer( &type->offsets, object ), (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) ); + } else + { + if (type->flags & CLASS_IS_IUNKNOWN && *(IUnknown**)object) + IUnknown_AddRef(*(IUnknown**)object); memmove( dest, get_this_pointer( &type->offsets, object ), type->size ); + } } } diff --git a/dlls/msvcrt/cppexcept.h b/dlls/msvcrt/cppexcept.h index 2bd2e2f9c62..21a7e6a8009 100644 --- a/dlls/msvcrt/cppexcept.h +++ b/dlls/msvcrt/cppexcept.h @@ -21,7 +21,10 @@ #ifndef __MSVCRT_CPPEXCEPT_H #define __MSVCRT_CPPEXCEPT_H +#define COBJMACROS + #include <fpieee.h> +#include "unknwn.h" #include "cxx.h" #define CXX_FRAME_MAGIC_VC6 0x19930520 @@ -132,6 +135,7 @@ typedef struct #define CLASS_IS_SIMPLE_TYPE 1 #define CLASS_HAS_VIRTUAL_BASE_CLASS 4 +#define CLASS_IS_IUNKNOWN 8 #define TYPE_FLAG_CONST 1 #define TYPE_FLAG_VOLATILE 2 @@ -244,6 +248,8 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, } else if (type->flags & CLASS_IS_SIMPLE_TYPE) { + if (type->flags & CLASS_IS_IUNKNOWN && *(IUnknown**)object) + IUnknown_AddRef(*(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 ); @@ -251,11 +257,17 @@ static inline void copy_exception( void *object, void **dest, UINT catch_flags, else /* copy the object */ { if (type->copy_ctor) + { call_copy_ctor( cxx_rva( type->copy_ctor, base ), dest, get_this_pointer( &type->offsets, object ), (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) ); + } else + { + if (type->flags & CLASS_IS_IUNKNOWN && *(IUnknown**)object) + IUnknown_AddRef(*(IUnknown**)object); memmove( dest, get_this_pointer( &type->offsets, object ), type->size ); + } } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9285
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/msvcp90/exception.c | 4 +--- dlls/msvcp90/msvcp90.h | 1 + dlls/msvcrt/exception_ptr.c | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/dlls/msvcp90/exception.c b/dlls/msvcp90/exception.c index 015d6e85da6..02b57de3ca8 100644 --- a/dlls/msvcp90/exception.c +++ b/dlls/msvcp90/exception.c @@ -1264,11 +1264,9 @@ void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) { if (ep->rec->ExceptionCode == CXX_EXCEPTION) { - const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2]; void *obj = (void*)ep->rec->ExceptionInformation[1]; - uintptr_t base = cxx_rva_base( type ); - if (type && type->destructor) call_dtor( cxx_rva(type->destructor, base), obj ); + __DestructExceptionObject(ep->rec); HeapFree(GetProcessHeap(), 0, obj); } diff --git a/dlls/msvcp90/msvcp90.h b/dlls/msvcp90/msvcp90.h index 7a4964712ec..97cd59952b4 100644 --- a/dlls/msvcp90/msvcp90.h +++ b/dlls/msvcp90/msvcp90.h @@ -733,6 +733,7 @@ static inline int mbstowcs_wrapper( size_t *ret, wchar_t *wcs, size_t size, cons #define hypotf( x, y ) ((float)hypot( (double)(x), (double)(y) )) #endif +void CDECL __DestructExceptionObject(EXCEPTION_RECORD*); void WINAPI DECLSPEC_NORETURN _CxxThrowException(void*,const cxx_exception_type*); void __cdecl DECLSPEC_NORETURN _Xinvalid_argument(const char*); void __cdecl DECLSPEC_NORETURN _Xlength_error(const char*); diff --git a/dlls/msvcrt/exception_ptr.c b/dlls/msvcrt/exception_ptr.c index dd2c6b0ac5c..383d16166aa 100644 --- a/dlls/msvcrt/exception_ptr.c +++ b/dlls/msvcrt/exception_ptr.c @@ -81,11 +81,9 @@ void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) { if (ep->rec->ExceptionCode == CXX_EXCEPTION) { - const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2]; void *obj = (void*)ep->rec->ExceptionInformation[1]; - uintptr_t base = cxx_rva_base( type ); - if (type && type->destructor) call_dtor( cxx_rva(type->destructor, base), obj ); + __DestructExceptionObject(ep->rec); HeapFree(GetProcessHeap(), 0, obj); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9285
participants (2)
-
Piotr Caban -
Piotr Caban (@piotr)