From 868e009e795037e741d5565f2c4c49442de731a1 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Tue, 6 May 2014 16:24:53 +0200 Subject: [PATCH] msvcrt: Add __ExceptionPtr* functions implementation. --- dlls/msvcr100/msvcr100.spec | 20 ++-- dlls/msvcr110/msvcr110.spec | 20 ++-- dlls/msvcrt/cpp.c | 220 ++++++++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+), 20 deletions(-) diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 0cc8fcbb7fe..98e953938bd 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -412,18 +412,18 @@ @ stub -arch=win64 ?__ExceptionPtrAssign@@YAXPEAXPEBX@Z @ stub -arch=win32 ?__ExceptionPtrCompare@@YA_NPBX0@Z @ stub -arch=win64 ?__ExceptionPtrCompare@@YA_NPEBX0@Z -@ stub -arch=win32 ?__ExceptionPtrCopy@@YAXPAXPBX@Z -@ stub -arch=win64 ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z +@ cdecl -arch=win32 ?__ExceptionPtrCopy@@YAXPAXPBX@Z(ptr ptr) __ExceptionPtrCopy +@ cdecl -arch=win64 ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z(ptr ptr) __ExceptionPtrCopy @ stub -arch=win32 ?__ExceptionPtrCopyException@@YAXPAXPBX1@Z @ stub -arch=win64 ?__ExceptionPtrCopyException@@YAXPEAXPEBX1@Z -@ stub -arch=win32 ?__ExceptionPtrCreate@@YAXPAX@Z -@ stub -arch=win64 ?__ExceptionPtrCreate@@YAXPEAX@Z -@ stub -arch=win32 ?__ExceptionPtrCurrentException@@YAXPAX@Z -@ stub -arch=win64 ?__ExceptionPtrCurrentException@@YAXPEAX@Z -@ stub -arch=win32 ?__ExceptionPtrDestroy@@YAXPAX@Z -@ stub -arch=win64 ?__ExceptionPtrDestroy@@YAXPEAX@Z -@ stub -arch=win32 ?__ExceptionPtrRethrow@@YAXPBX@Z -@ stub -arch=win64 ?__ExceptionPtrRethrow@@YAXPEBX@Z +@ cdecl -arch=win32 ?__ExceptionPtrCreate@@YAXPAX@Z(ptr) __ExceptionPtrCreate +@ cdecl -arch=win64 ?__ExceptionPtrCreate@@YAXPEAX@Z(ptr) __ExceptionPtrCreate +@ cdecl -arch=win32 ?__ExceptionPtrCurrentException@@YAXPAX@Z(ptr) __ExceptionPtrCurrentException +@ cdecl -arch=win64 ?__ExceptionPtrCurrentException@@YAXPEAX@Z(ptr) __ExceptionPtrCurrentException +@ cdecl -arch=win32 ?__ExceptionPtrDestroy@@YAXPAX@Z(ptr) __ExceptionPtrDestroy +@ cdecl -arch=win64 ?__ExceptionPtrDestroy@@YAXPEAX@Z(ptr) __ExceptionPtrDestroy +@ cdecl -arch=win32 ?__ExceptionPtrRethrow@@YAXPBX@Z(ptr) __ExceptionPtrRethrow +@ cdecl -arch=win64 ?__ExceptionPtrRethrow@@YAXPEBX@Z(ptr) __ExceptionPtrRethrow @ cdecl __uncaught_exception() MSVCRT___uncaught_exception @ stub ?_inconsistency@@YAXXZ @ cdecl -arch=win32 ?_invalid_parameter@@YAXPBG00II@Z(wstr wstr wstr long long) MSVCRT__invalid_parameter diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec index 3d24b0f608e..cdca5c32b37 100644 --- a/dlls/msvcr110/msvcr110.spec +++ b/dlls/msvcr110/msvcr110.spec @@ -690,18 +690,18 @@ @ stub -arch=win64 ?__ExceptionPtrAssign@@YAXPEAXPEBX@Z @ stub -arch=win32 ?__ExceptionPtrCompare@@YA_NPBX0@Z @ stub -arch=win64 ?__ExceptionPtrCompare@@YA_NPEBX0@Z -@ stub -arch=win32 ?__ExceptionPtrCopy@@YAXPAXPBX@Z -@ stub -arch=win64 ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z +@ cdecl -arch=win32 ?__ExceptionPtrCopy@@YAXPAXPBX@Z(ptr ptr) __ExceptionPtrCopy +@ cdecl -arch=win64 ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z(ptr ptr) __ExceptionPtrCopy @ stub -arch=win32 ?__ExceptionPtrCopyException@@YAXPAXPBX1@Z @ stub -arch=win64 ?__ExceptionPtrCopyException@@YAXPEAXPEBX1@Z -@ stub -arch=win32 ?__ExceptionPtrCreate@@YAXPAX@Z -@ stub -arch=win64 ?__ExceptionPtrCreate@@YAXPEAX@Z -@ stub -arch=win32 ?__ExceptionPtrCurrentException@@YAXPAX@Z -@ stub -arch=win64 ?__ExceptionPtrCurrentException@@YAXPEAX@Z -@ stub -arch=win32 ?__ExceptionPtrDestroy@@YAXPAX@Z -@ stub -arch=win64 ?__ExceptionPtrDestroy@@YAXPEAX@Z -@ stub -arch=win32 ?__ExceptionPtrRethrow@@YAXPBX@Z -@ stub -arch=win64 ?__ExceptionPtrRethrow@@YAXPEBX@Z +@ cdecl -arch=win32 ?__ExceptionPtrCreate@@YAXPAX@Z(ptr) __ExceptionPtrCreate +@ cdecl -arch=win64 ?__ExceptionPtrCreate@@YAXPEAX@Z(ptr) __ExceptionPtrCreate +@ cdecl -arch=win32 ?__ExceptionPtrCurrentException@@YAXPAX@Z(ptr) __ExceptionPtrCurrentException +@ cdecl -arch=win64 ?__ExceptionPtrCurrentException@@YAXPEAX@Z(ptr) __ExceptionPtrCurrentException +@ cdecl -arch=win32 ?__ExceptionPtrDestroy@@YAXPAX@Z(ptr) __ExceptionPtrDestroy +@ cdecl -arch=win64 ?__ExceptionPtrDestroy@@YAXPEAX@Z(ptr) __ExceptionPtrDestroy +@ cdecl -arch=win32 ?__ExceptionPtrRethrow@@YAXPBX@Z(ptr) __ExceptionPtrRethrow +@ cdecl -arch=win64 ?__ExceptionPtrRethrow@@YAXPEBX@Z(ptr) __ExceptionPtrRethrow @ stub -arch=win32 ?__ExceptionPtrSwap@@YAXPAX0@Z @ stub -arch=win64 ?__ExceptionPtrSwap@@YAXPEAX0@Z @ stub -arch=win32 ?__ExceptionPtrToBool@@YA_NPBX@Z diff --git a/dlls/msvcrt/cpp.c b/dlls/msvcrt/cpp.c index 50c2681270a..37dc18af054 100644 --- a/dlls/msvcrt/cpp.c +++ b/dlls/msvcrt/cpp.c @@ -1211,3 +1211,223 @@ const char * __thiscall type_info_name_internal_method(type_info * _this, struct return MSVCRT_type_info_name(_this); } + +/* std::exception_ptr class helpers */ +typedef struct +{ + EXCEPTION_RECORD *rec; + int *ref; /* not binary compatible with native msvcr100 */ +} exception_ptr; + +/********************************************************************* + * ?__ExceptionPtrCreate@@YAXPAX@Z + * ?__ExceptionPtrCreate@@YAXPEAX@Z + */ +void __cdecl __ExceptionPtrCreate(exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + + ep->rec = NULL; + ep->ref = NULL; +} + +#ifdef __i386__ +static inline void call_dtor(const cxx_exception_type *type, void *func, void *object) +{ + __asm__ __volatile__("call *%0" : : "m" (func), "c" (object) : "eax", "edx", "memory"); +} +#elif __x86_64__ +static inline void call_dtor(const cxx_exception_type *type, unsigned int dtor, void *object) +{ + char *base = RtlPcToFileHeader((void*)type, (void**)&base); + void (__cdecl *func)(void*) = (void*)(base + dtor); + func(object); +} +#else +#define call_dtor(type, func, object) ((void (__cdecl*)(void*))(func))(object) +#endif + +/********************************************************************* + * ?__ExceptionPtrDestroy@@YAXPAX@Z + * ?__ExceptionPtrDestroy@@YAXPEAX@Z + */ +void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + + if (!ep->rec) + return; + + if (!InterlockedDecrement(ep->ref)) + { + if (ep->rec->ExceptionCode == CXX_EXCEPTION) + { + const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2]; + void *obj = (void*)ep->rec->ExceptionInformation[1]; + + if (type && type->destructor) call_dtor(type, type->destructor, obj); + HeapFree(GetProcessHeap(), 0, obj); + } + + HeapFree(GetProcessHeap(), 0, ep->rec); + HeapFree(GetProcessHeap(), 0, ep->ref); + } +} + +/********************************************************************* + * ?__ExceptionPtrCopy@@YAXPAXPBX@Z + * ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z + */ +void __cdecl __ExceptionPtrCopy(exception_ptr *ep, const exception_ptr *copy) +{ + TRACE("(%p %p)\n", ep, copy); + + /* don't destroy object stored in ep */ + *ep = *copy; + if (ep->ref) + InterlockedIncrement(copy->ref); +} + +/********************************************************************* + * ?__ExceptionPtrRethrow@@YAXPBX@Z + * ?__ExceptionPtrRethrow@@YAXPEBX@Z + */ +void __cdecl __ExceptionPtrRethrow(const exception_ptr *ep) +{ + TRACE("(%p)\n", ep); + + if (!ep->rec) + { + static const char *exception_msg = "bad exception"; + exception e; + + MSVCRT_exception_ctor(&e, &exception_msg); + _CxxThrowException(&e, &exception_exception_type); + return; + } + + RaiseException(ep->rec->ExceptionCode, ep->rec->ExceptionFlags & (~EH_UNWINDING), + ep->rec->NumberParameters, ep->rec->ExceptionInformation); +} + +#ifdef __i386__ +static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase ) +{ + TRACE( "calling copy ctor %p object %p src %p\n", func, this, src ); + if (has_vbase) + /* in that case copy ctor takes an extra bool indicating whether to copy the base class */ + __asm__ __volatile__("pushl $1; pushl %2; call *%0" + : : "m" (func), "c" (this), "m" (src) : "eax", "edx", "memory" ); + else + __asm__ __volatile__("pushl %2; call *%0" + : : "m" (func), "c" (this), "m" (src) : "eax", "edx", "memory" ); +} +#else +static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase ) +{ + TRACE( "calling copy ctor %p object %p src %p\n", func, this, src ); + if (has_vbase) + ((void (__cdecl*)(void*, void*, BOOL))func)(this, src, 1); + else + ((void (__cdecl*)(void*, void*))func)(this, src); +} +#endif + +/********************************************************************* + * ?__ExceptionPtrCurrentException@@YAXPAX@Z + * ?__ExceptionPtrCurrentException@@YAXPEAX@Z + */ +#ifndef __x86_64__ +void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +{ + EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; + + TRACE("(%p)\n", ep); + + if (!rec) + { + ep->rec = NULL; + ep->ref = NULL; + return; + } + + ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); + ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); + + *ep->rec = *rec; + *ep->ref = 1; + + if (ep->rec->ExceptionCode == CXX_EXCEPTION) + { + const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2]; + const cxx_type_info *ti; + void **data, *obj; + + ti = et->type_info_table->info[0]; + data = HeapAlloc(GetProcessHeap(), 0, ti->size); + + obj = (void*)ep->rec->ExceptionInformation[1]; + 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(ti->copy_ctor, 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); + ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; + } + return; +} +#else +void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep) +{ + EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record; + + TRACE("(%p)\n", ep); + + if (!rec) + { + ep->rec = NULL; + ep->ref = NULL; + return; + } + + ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD)); + ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int)); + + *ep->rec = *rec; + *ep->ref = 1; + + if (ep->rec->ExceptionCode == CXX_EXCEPTION) + { + const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2]; + const cxx_type_info *ti; + void **data, *obj; + char *base = RtlPcToFileHeader((void*)et, (void**)&base); + + ti = (const cxx_type_info*)(base + ((const cxx_type_info_table*)(base + et->type_info_table))->info[0]); + data = HeapAlloc(GetProcessHeap(), 0, ti->size); + + obj = (void*)ep->rec->ExceptionInformation[1]; + 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(base + ti->copy_ctor, 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); + ep->rec->ExceptionInformation[1] = (ULONG_PTR)data; + } + return; +} +#endif