type_info is needed for RTTI, and in some cases pulling in whole exception.c is not an option due to its dependency on multiple MSVCRT_ functions.
Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com --- dlls/msvcirt/Makefile.in | 1 + dlls/msvcirt/msvcirt.c | 1 + dlls/msvcirt/msvcirt.h | 1 + dlls/msvcp100/Makefile.in | 1 + dlls/msvcp110/Makefile.in | 1 + dlls/msvcp120/Makefile.in | 1 + dlls/msvcp140/Makefile.in | 1 + dlls/msvcp60/Makefile.in | 1 + dlls/msvcp60/main.c | 1 + dlls/msvcp60/msvcp.h | 1 + dlls/msvcp70/Makefile.in | 1 + dlls/msvcp71/Makefile.in | 1 + dlls/msvcp80/Makefile.in | 1 + dlls/msvcp90/Makefile.in | 1 + dlls/msvcp90/exception.c | 31 ------------------ dlls/msvcp90/msvcp90.h | 1 + dlls/msvcp90/msvcp_main.c | 1 + dlls/msvcp90/type_info.c | 67 +++++++++++++++++++++++++++++++++++++++ 18 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 dlls/msvcp90/type_info.c
diff --git a/dlls/msvcirt/Makefile.in b/dlls/msvcirt/Makefile.in index 1dee2b24c02..b792edabf09 100644 --- a/dlls/msvcirt/Makefile.in +++ b/dlls/msvcirt/Makefile.in @@ -6,5 +6,6 @@ IMPORTS = msvcrt EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native
C_SRCS = \ + type_info.c \ exception.c \ msvcirt.c diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c index db4b736d272..87e1908c4a8 100644 --- a/dlls/msvcirt/msvcirt.c +++ b/dlls/msvcirt/msvcirt.c @@ -5213,6 +5213,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { case DLL_PROCESS_ATTACH: init_cxx_funcs(); + init_type_info(inst); init_exception(inst); init_io(inst); DisableThreadLibraryCalls( inst ); diff --git a/dlls/msvcirt/msvcirt.h b/dlls/msvcirt/msvcirt.h index 5b59b7862a3..e775eabb2fe 100644 --- a/dlls/msvcirt/msvcirt.h +++ b/dlls/msvcirt/msvcirt.h @@ -71,4 +71,5 @@ typedef enum { extern void* (__cdecl *MSVCRT_operator_new)(SIZE_T); extern void (__cdecl *MSVCRT_operator_delete)(void*);
+void init_type_info(void*); void init_exception(void*); diff --git a/dlls/msvcp100/Makefile.in b/dlls/msvcp100/Makefile.in index 258aff4b770..0ee8fee26c8 100644 --- a/dlls/msvcp100/Makefile.in +++ b/dlls/msvcp100/Makefile.in @@ -6,6 +6,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp110/Makefile.in b/dlls/msvcp110/Makefile.in index 6b1998a68ea..01a22340b6d 100644 --- a/dlls/msvcp110/Makefile.in +++ b/dlls/msvcp110/Makefile.in @@ -6,6 +6,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp120/Makefile.in b/dlls/msvcp120/Makefile.in index 2a77859bf99..22923b61937 100644 --- a/dlls/msvcp120/Makefile.in +++ b/dlls/msvcp120/Makefile.in @@ -6,6 +6,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp140/Makefile.in b/dlls/msvcp140/Makefile.in index ea05d6b3456..00bc6e219ce 100644 --- a/dlls/msvcp140/Makefile.in +++ b/dlls/msvcp140/Makefile.in @@ -5,6 +5,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp60/Makefile.in b/dlls/msvcp60/Makefile.in index b43395b44d1..92188139b02 100644 --- a/dlls/msvcp60/Makefile.in +++ b/dlls/msvcp60/Makefile.in @@ -6,6 +6,7 @@ IMPORTS = msvcrt EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp60/main.c b/dlls/msvcp60/main.c index ab9a6a3179d..a553e1438c2 100644 --- a/dlls/msvcp60/main.c +++ b/dlls/msvcp60/main.c @@ -89,6 +89,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: init_cxx_funcs(); _Init_locks__Init_locks_ctor(NULL); + init_type_info(hinstDLL); init_exception(hinstDLL); init_locale(hinstDLL); init_io(hinstDLL); diff --git a/dlls/msvcp60/msvcp.h b/dlls/msvcp60/msvcp.h index 2507d9123d9..f078b33542a 100644 --- a/dlls/msvcp60/msvcp.h +++ b/dlls/msvcp60/msvcp.h @@ -465,6 +465,7 @@ ostreambuf_iterator_wchar* __thiscall num_put_wchar_put_uint64(const num_put*, o ostreambuf_iterator_wchar* __thiscall num_put_wchar_put_bool(const num_put*, ostreambuf_iterator_wchar*, ostreambuf_iterator_wchar, ios_base*, wchar_t, bool);
+void init_type_info(void*); void init_exception(void*); void init_locale(void*); void init_io(void*); diff --git a/dlls/msvcp70/Makefile.in b/dlls/msvcp70/Makefile.in index a023d1b8e2a..57987596f50 100644 --- a/dlls/msvcp70/Makefile.in +++ b/dlls/msvcp70/Makefile.in @@ -6,6 +6,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp71/Makefile.in b/dlls/msvcp71/Makefile.in index 6713ab469d3..743b6d4751c 100644 --- a/dlls/msvcp71/Makefile.in +++ b/dlls/msvcp71/Makefile.in @@ -6,6 +6,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp80/Makefile.in b/dlls/msvcp80/Makefile.in index 22a18fcc66a..7c1947f2721 100644 --- a/dlls/msvcp80/Makefile.in +++ b/dlls/msvcp80/Makefile.in @@ -6,6 +6,7 @@ PARENTSRC = ../msvcp90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp90/Makefile.in b/dlls/msvcp90/Makefile.in index b7e7b73423f..fe4bec04a9c 100644 --- a/dlls/msvcp90/Makefile.in +++ b/dlls/msvcp90/Makefile.in @@ -5,6 +5,7 @@ EXTRADEFS = -D_MSVCP_VER=90 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + type_info.c \ exception.c \ ios.c \ locale.c \ diff --git a/dlls/msvcp90/exception.c b/dlls/msvcp90/exception.c index 8ea4e132a0f..e6c9227cc27 100644 --- a/dlls/msvcp90/exception.c +++ b/dlls/msvcp90/exception.c @@ -65,34 +65,6 @@ extern const vtable_ptr MSVCP_bad_cast_vtable; /* ??_7range_error@std@@6B@ */ extern const vtable_ptr MSVCP_range_error_vtable;
-static void MSVCP_type_info_dtor(type_info * _this) -{ - free(_this->name); -} - -/* Unexported */ -DEFINE_THISCALL_WRAPPER(MSVCP_type_info_vector_dtor,8) -void * __thiscall MSVCP_type_info_vector_dtor(type_info * _this, unsigned int flags) -{ - TRACE("(%p %x)\n", _this, flags); - if (flags & 2) - { - /* we have an array, with the number of elements stored before the first object */ - INT_PTR i, *ptr = (INT_PTR *)_this - 1; - - for (i = *ptr - 1; i >= 0; i--) MSVCP_type_info_dtor(_this + i); - MSVCRT_operator_delete(ptr); - } - else - { - MSVCP_type_info_dtor(_this); - if (flags & 1) MSVCRT_operator_delete(_this); - } - return _this; -} - -DEFINE_RTTI_DATA0( type_info, 0, ".?AVtype_info@@" ) - /* ??0exception@@QAE@ABQBD@Z */ /* ??0exception@@QEAA@AEBQEBD@Z */ DEFINE_THISCALL_WRAPPER(MSVCP_exception_ctor,8) @@ -1022,8 +994,6 @@ void __cdecl __ExceptionPtrDestroy(exception_ptr *ep) #endif
__ASM_BLOCK_BEGIN(exception_vtables) - __ASM_VTABLE(type_info, - VTABLE_ADD_FUNC(MSVCP_type_info_vector_dtor)); EXCEPTION_VTABLE(exception, VTABLE_ADD_FUNC(MSVCP_exception_vector_dtor) VTABLE_ADD_FUNC(MSVCP_exception_what)); @@ -1130,7 +1100,6 @@ void throw_exception(exception_type et, const char *str) void init_exception(void *base) { #ifdef __x86_64__ - init_type_info_rtti(base); init_exception_rtti(base); init_bad_alloc_rtti(base); init_logic_error_rtti(base); diff --git a/dlls/msvcp90/msvcp90.h b/dlls/msvcp90/msvcp90.h index b2e0ae8b15c..c4908f24245 100644 --- a/dlls/msvcp90/msvcp90.h +++ b/dlls/msvcp90/msvcp90.h @@ -618,6 +618,7 @@ ostreambuf_iterator_wchar* __thiscall num_put_wchar_put_uint64(const num_put*, o ostreambuf_iterator_wchar* __thiscall num_put_wchar_put_bool(const num_put*, ostreambuf_iterator_wchar*, ostreambuf_iterator_wchar, ios_base*, wchar_t, bool);
+void init_type_info(void*); void init_exception(void*); void init_locale(void*); void init_io(void*); diff --git a/dlls/msvcp90/msvcp_main.c b/dlls/msvcp90/msvcp_main.c index 6bfd8b14367..b023a3573de 100644 --- a/dlls/msvcp90/msvcp_main.c +++ b/dlls/msvcp90/msvcp_main.c @@ -184,6 +184,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: init_cxx_funcs(); _Init_locks__Init_locks_ctor(NULL); + init_type_info(hinstDLL); init_exception(hinstDLL); init_locale(hinstDLL); init_io(hinstDLL); diff --git a/dlls/msvcp90/type_info.c b/dlls/msvcp90/type_info.c new file mode 100644 index 00000000000..38134ac5e86 --- /dev/null +++ b/dlls/msvcp90/type_info.c @@ -0,0 +1,67 @@ +/* + * Copyright 2021 Arkadiusz Hiler for CodeWeavers + * + * 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 "msvcp90.h" +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msvcp); + +static void MSVCP_type_info_dtor(type_info * _this) +{ + free(_this->name); +} + +/* Unexported */ +DEFINE_THISCALL_WRAPPER(MSVCP_type_info_vector_dtor,8) +void * __thiscall MSVCP_type_info_vector_dtor(type_info * _this, unsigned int flags) +{ + TRACE("(%p %x)\n", _this, flags); + if (flags & 2) + { + /* we have an array, with the number of elements stored before the first object */ + INT_PTR i, *ptr = (INT_PTR *)_this - 1; + + for (i = *ptr - 1; i >= 0; i--) MSVCP_type_info_dtor(_this + i); + MSVCRT_operator_delete(ptr); + } + else + { + MSVCP_type_info_dtor(_this); + if (flags & 1) MSVCRT_operator_delete(_this); + } + return _this; +} + +DEFINE_RTTI_DATA0( type_info, 0, ".?AVtype_info@@" ) + +__ASM_BLOCK_BEGIN(type_info_vtables) + __ASM_VTABLE(type_info, + VTABLE_ADD_FUNC(MSVCP_type_info_vector_dtor)); +__ASM_BLOCK_END + +void init_type_info(void *base) +{ +#ifdef __x86_64__ + init_type_info_rtti(base); +#endif +}
This backs C++17's std::pmr implementation.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49954 Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com --- configure | 1 + configure.ac | 1 + dlls/msvcp140_1/Makefile.in | 9 +- dlls/msvcp140_1/msvcp140_1.c | 266 +++++++++++++++++++++++++++ dlls/msvcp140_1/msvcp140_1.spec | 14 +- dlls/msvcp140_1/tests/Makefile.in | 3 + dlls/msvcp140_1/tests/msvcp140_1.c | 277 +++++++++++++++++++++++++++++ 7 files changed, 563 insertions(+), 8 deletions(-) create mode 100644 dlls/msvcp140_1/msvcp140_1.c create mode 100644 dlls/msvcp140_1/tests/Makefile.in create mode 100644 dlls/msvcp140_1/tests/msvcp140_1.c
diff --git a/configure b/configure index a19bb0b9581..aedbac67fe4 100755 --- a/configure +++ b/configure @@ -20825,6 +20825,7 @@ wine_fn_config_makefile dlls/msvcp120_app enable_msvcp120_app wine_fn_config_makefile dlls/msvcp140 enable_msvcp140 wine_fn_config_makefile dlls/msvcp140/tests enable_tests wine_fn_config_makefile dlls/msvcp140_1 enable_msvcp140_1 +wine_fn_config_makefile dlls/msvcp140_1/tests enable_tests wine_fn_config_makefile dlls/msvcp60 enable_msvcp60 wine_fn_config_makefile dlls/msvcp60/tests enable_tests wine_fn_config_makefile dlls/msvcp70 enable_msvcp70 diff --git a/configure.ac b/configure.ac index eb08e8b0f17..edd7be66ec3 100644 --- a/configure.ac +++ b/configure.ac @@ -3500,6 +3500,7 @@ WINE_CONFIG_MAKEFILE(dlls/msvcp120_app) WINE_CONFIG_MAKEFILE(dlls/msvcp140) WINE_CONFIG_MAKEFILE(dlls/msvcp140/tests) WINE_CONFIG_MAKEFILE(dlls/msvcp140_1) +WINE_CONFIG_MAKEFILE(dlls/msvcp140_1/tests) WINE_CONFIG_MAKEFILE(dlls/msvcp60) WINE_CONFIG_MAKEFILE(dlls/msvcp60/tests) WINE_CONFIG_MAKEFILE(dlls/msvcp70) diff --git a/dlls/msvcp140_1/Makefile.in b/dlls/msvcp140_1/Makefile.in index 6582299d7d6..846bcdc855b 100644 --- a/dlls/msvcp140_1/Makefile.in +++ b/dlls/msvcp140_1/Makefile.in @@ -1 +1,8 @@ -MODULE = msvcp140_1.dll +MODULE = msvcp140_1.dll +PARENTSRC = ../msvcp90 + +EXTRADLLFLAGS = -mno-cygwin -fno-builtin + +C_SRCS = \ + type_info.c \ + msvcp140_1.c diff --git a/dlls/msvcp140_1/msvcp140_1.c b/dlls/msvcp140_1/msvcp140_1.c new file mode 100644 index 00000000000..344fee3dc53 --- /dev/null +++ b/dlls/msvcp140_1/msvcp140_1.c @@ -0,0 +1,266 @@ +/* + * Copyright 2021 Arkadiusz Hiler for CodeWeavers + * + * 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 <stdbool.h> +#include <malloc.h> + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "winnls.h" +#include "cxx.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msvcp); + +#ifdef __i386__ +#define MAX_UNALIGNED_ALIGNMENT 8 +#else +#define MAX_UNALIGNED_ALIGNMENT 16 +#endif + +static HMODULE msvcp140; + +void init_type_info(void *base); +int CDECL _callnewh(size_t size); + +void (__cdecl *throw_bad_alloc)(void); + +/* non-static, needed by type_info */ +void* __cdecl MSVCRT_operator_new(size_t size) +{ + void *retval; + int freed; + + do + { + retval = malloc(size); + if (retval) + { + TRACE("(%Iu) returning %p\n", size, retval); + return retval; + } + freed = _callnewh(size); + } while (freed); + + TRACE("(%Iu) out of memory\n", size); + throw_bad_alloc(); + return NULL; +} + +void __cdecl MSVCRT_operator_delete(void *mem) +{ + free(mem); +} + +static void* __cdecl MSVCRT_operator_new_aligned(size_t size, size_t alignment) +{ + void *retval; + int freed; + + do + { + retval = _aligned_malloc(size, alignment); + if (retval) + { + TRACE("(%Iu) returning %p\n", size, retval); + return retval; + } + freed = _callnewh(size); + } while (freed); + + TRACE("(%Iu) out of memory\n", size); + throw_bad_alloc(); + return NULL; +} + +static void __cdecl MSVCRT_operator_delete_aligned(void *mem, size_t alignment) +{ + _aligned_free(mem); +} + +typedef struct { + const vtable_ptr *vtable; +} memory_resource; + +extern const vtable_ptr MSVCP_aligned_resource_vtable; +extern const vtable_ptr MSVCP_unaligned_resource_vtable; +extern const vtable_ptr MSVCP_null_resource_vtable; + +__ASM_BLOCK_BEGIN(vtables) + __ASM_VTABLE(base_memory_resource, + VTABLE_ADD_FUNC(nop_dtor)); + __ASM_VTABLE(aligned_resource, + VTABLE_ADD_FUNC(nop_dtor) + VTABLE_ADD_FUNC(aligned_do_allocate) + VTABLE_ADD_FUNC(aligned_do_deallocate) + VTABLE_ADD_FUNC(do_is_equal)); + __ASM_VTABLE(unaligned_resource, + VTABLE_ADD_FUNC(nop_dtor) + VTABLE_ADD_FUNC(unaligned_do_allocate) + VTABLE_ADD_FUNC(unaligned_do_deallocate) + VTABLE_ADD_FUNC(do_is_equal)); + __ASM_VTABLE(null_resource, + VTABLE_ADD_FUNC(nop_dtor) + VTABLE_ADD_FUNC(null_do_allocate) + VTABLE_ADD_FUNC(null_do_deallocate) + VTABLE_ADD_FUNC(do_is_equal)); +__ASM_BLOCK_END + +DEFINE_RTTI_DATA0(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") +DEFINE_RTTI_DATA1(aligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Aligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(unaligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Unligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(null_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_null_resource@pmr@std@@") + +DEFINE_THISCALL_WRAPPER(nop_dtor, 4) +void __thiscall nop_dtor(void *this) +{ + /* nop */ +} + +DEFINE_THISCALL_WRAPPER(do_is_equal, 8) +bool __thiscall do_is_equal(memory_resource *this, memory_resource *other) +{ + return this == other; +} + +DEFINE_THISCALL_WRAPPER(aligned_do_allocate, 12) +void* __thiscall aligned_do_allocate(memory_resource *this, size_t bytes, size_t alignment) +{ + return MSVCRT_operator_new_aligned(bytes, alignment); +} + +DEFINE_THISCALL_WRAPPER(aligned_do_deallocate, 16) +void __thiscall aligned_do_deallocate(memory_resource *this, void *p, size_t bytes, size_t alignment) +{ + MSVCRT_operator_delete_aligned(p, alignment); +} + +DEFINE_THISCALL_WRAPPER(unaligned_do_allocate, 12) +void* __thiscall unaligned_do_allocate(memory_resource *this, size_t bytes, size_t alignment) +{ + if (alignment > MAX_UNALIGNED_ALIGNMENT) + throw_bad_alloc(); + + return MSVCRT_operator_new(bytes); +} + +DEFINE_THISCALL_WRAPPER(unaligned_do_deallocate, 16) +void __thiscall unaligned_do_deallocate(memory_resource *this, void *p, size_t bytes, size_t alignment) +{ + MSVCRT_operator_delete(p); +} + +DEFINE_THISCALL_WRAPPER(null_do_allocate, 12) +void* __thiscall null_do_allocate(memory_resource *this, size_t bytes, size_t alignment) +{ + throw_bad_alloc(); + return NULL; +} + +DEFINE_THISCALL_WRAPPER(null_do_deallocate, 16) +void __thiscall null_do_deallocate(memory_resource *this, void *p, size_t bytes, size_t alignment) +{ + /* nop */ +} + +static memory_resource impl_aligned_resource = { &MSVCP_aligned_resource_vtable }; +static memory_resource impl_unaligned_resource = { &MSVCP_unaligned_resource_vtable }; +static memory_resource impl_null_resource = { &MSVCP_null_resource_vtable }; + +memory_resource *default_unaligned_resource = &impl_unaligned_resource; +memory_resource *default_aligned_resource = &impl_aligned_resource; + +/* EXPORTS */ + +memory_resource* __cdecl _Aligned_new_delete_resource(void) +{ + return &impl_aligned_resource; +} + +memory_resource* __cdecl _Unaligned_new_delete_resource(void) +{ + return &impl_unaligned_resource; +} + +memory_resource* __cdecl _Aligned_get_default_resource(void) +{ + return default_aligned_resource; +} + +memory_resource* __cdecl _Aligned_set_default_resource(memory_resource *res) +{ + if (res == NULL) + res = &impl_aligned_resource; + + return InterlockedExchangePointer((void**)&default_aligned_resource, res); +} + +memory_resource* __cdecl _Unaligned_get_default_resource(void) +{ + return default_unaligned_resource; +} + +memory_resource* __cdecl _Unaligned_set_default_resource(memory_resource *res) +{ + if (res == NULL) + res = &impl_unaligned_resource; + + return InterlockedExchangePointer((void**)&default_unaligned_resource, res); +} + +memory_resource* __cdecl null_memory_resource(void) +{ + return &impl_null_resource; +} + +/* DLL INIT */ + +static void init_cxx_funcs(void) +{ + msvcp140 = LoadLibraryA("msvcp140.dll"); + if (!msvcp140) FIXME("Failed to load msvcp140.dll\n"); + throw_bad_alloc = (void*)GetProcAddress(msvcp140, "?_Xbad_alloc@std@@YAXXZ"); + if (!throw_bad_alloc) FIXME("Failed to get address of ?_Xbad_alloc@std@@YAXXZ\n"); +} + +static void init_memory_resource(void *base) +{ +#ifdef __x86_64__ + init_null_resource_rtti(base); + init_unaligned_resource_rtti(base); + init_aligned_resource_rtti(base); + init_base_memory_resource_rtti(base); +#endif +} + +BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + init_cxx_funcs(); + init_type_info(inst); + init_memory_resource(inst); + break; + case DLL_PROCESS_DETACH: + FreeLibrary(msvcp140); + break; + } + return TRUE; +} diff --git a/dlls/msvcp140_1/msvcp140_1.spec b/dlls/msvcp140_1/msvcp140_1.spec index bfe82ab00da..e4446f4f4c2 100644 --- a/dlls/msvcp140_1/msvcp140_1.spec +++ b/dlls/msvcp140_1/msvcp140_1.spec @@ -1,7 +1,7 @@ -@ stub _Aligned_get_default_resource -@ stub _Aligned_new_delete_resource -@ stub _Aligned_set_default_resource -@ stub _Unaligned_get_default_resource -@ stub _Unaligned_new_delete_resource -@ stub _Unaligned_set_default_resource -@ stub null_memory_resource +@ cdecl _Aligned_get_default_resource() +@ cdecl _Aligned_new_delete_resource() +@ cdecl _Aligned_set_default_resource(ptr) +@ cdecl _Unaligned_get_default_resource() +@ cdecl _Unaligned_new_delete_resource() +@ cdecl _Unaligned_set_default_resource(ptr) +@ cdecl null_memory_resource() diff --git a/dlls/msvcp140_1/tests/Makefile.in b/dlls/msvcp140_1/tests/Makefile.in new file mode 100644 index 00000000000..523a2016d3a --- /dev/null +++ b/dlls/msvcp140_1/tests/Makefile.in @@ -0,0 +1,3 @@ +TESTDLL = msvcp140_1.dll + +C_SRCS = msvcp140_1.c diff --git a/dlls/msvcp140_1/tests/msvcp140_1.c b/dlls/msvcp140_1/tests/msvcp140_1.c new file mode 100644 index 00000000000..a32dd364fe8 --- /dev/null +++ b/dlls/msvcp140_1/tests/msvcp140_1.c @@ -0,0 +1,277 @@ +/* + * Copyright 2021 Arkadiusz Hiler for CodeWeavers + * + * 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 <errno.h> +#include <stdio.h> + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" + +#include "wine/test.h" +#include "wine/exception.h" +#include "winbase.h" + +typedef unsigned char MSVCP_bool; + +#undef __thiscall +#ifdef __i386__ +#define __thiscall __stdcall +#else +#define __thiscall __cdecl +#endif + +#ifdef __i386__ +#define MAX_UNALIGNED_ALIGNMENT 8 +#else +#define MAX_UNALIGNED_ALIGNMENT 16 +#endif + +/* Emulate __thiscall */ +#ifdef __i386__ + +#include "pshpack1.h" +struct thiscall_thunk +{ + BYTE pop_eax; /* popl %eax (ret addr) */ + BYTE pop_edx; /* popl %edx (func) */ + BYTE pop_ecx; /* popl %ecx (this) */ + BYTE push_eax; /* pushl %eax */ + WORD jmp_edx; /* jmp *%edx */ +}; +#include "poppack.h" + +static void* (WINAPI *call_thiscall_func1)(void *func, void *this); +static void* (WINAPI *call_thiscall_func2)(void *func, void *this, const void *a); +static void* (WINAPI *call_thiscall_func3)(void *func, void *this, const void *a, const void *b); +static void* (WINAPI *call_thiscall_func4)(void *func, void *this, const void *a, const void *b, const void *c); + +static void init_thiscall_thunk(void) +{ + struct thiscall_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + thunk->pop_eax = 0x58; /* popl %eax */ + thunk->pop_edx = 0x5a; /* popl %edx */ + thunk->pop_ecx = 0x59; /* popl %ecx */ + thunk->push_eax = 0x50; /* pushl %eax */ + thunk->jmp_edx = 0xe2ff; /* jmp *%edx */ + call_thiscall_func1 = (void*)thunk; + call_thiscall_func2 = (void*)thunk; + call_thiscall_func3 = (void*)thunk; + call_thiscall_func4 = (void*)thunk; +} + +#define call_func1(func,_this) call_thiscall_func1(func,_this) +#define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a)) +#define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)(a),(const void*)(b)) +#define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,(const void*)(a),(const void*)(b), (const void*)(c)) + +#else + +#define init_thiscall_thunk() +#define call_func1(func,_this) func(_this) +#define call_func2(func,_this,a) func(_this,a) +#define call_func3(func,_this,a,b) func(_this,a,b) +#define call_func4(func,_this,a,b,c) func(_this,a,b,c) + +#endif /* __i386__ */ + +struct memory_resource_vtbl; + +typedef struct { + struct memory_resource_vtbl *vtbl; +} memory_resource; + +struct memory_resource_vtbl +{ + void (__thiscall *dtor)(void *this); + void* (__thiscall *do_allocate)(memory_resource *this, size_t bytes, size_t alignment); + void (__thiscall *do_deallocate)(memory_resource *this, void *p, size_t bytes, size_t alignment); + MSVCP_bool (__thiscall *do_is_equal)(memory_resource *this, memory_resource *other); +}; + +static HMODULE msvcp; +static memory_resource* (__cdecl *p__Aligned_new_delete_resource)(void); +static memory_resource* (__cdecl *p__Unaligned_new_delete_resource)(void); +static memory_resource* (__cdecl *p__Aligned_get_default_resource)(void); +static memory_resource* (__cdecl *p__Unaligned_get_default_resource)(void); +static memory_resource* (__cdecl *p__Aligned_set_default_resource)(memory_resource* resource); +static memory_resource* (__cdecl *p__Unaligned_set_default_resource)(memory_resource* resource); +static memory_resource* (__cdecl *p_null_memory_resource)(void); + +static HMODULE ucrtbase; +static void* (__cdecl *p_malloc)(size_t size); +static void (__cdecl *p_free)(void *ptr); +static void* (__cdecl *p__aligned_malloc)(size_t size, size_t alignment); +static void (__cdecl *p__aligned_free)(void *ptr); + +#define SETNOFAIL(lib,x,y) x = (void*)GetProcAddress(lib,y) +#define SET(lib,x,y) do { SETNOFAIL(lib,x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) + +static BOOL init(void) +{ + msvcp = LoadLibraryA("msvcp140_1.dll"); + if(!msvcp) + { + win_skip("msvcp140_1.dll not installed\n"); + return FALSE; + } + + ucrtbase = LoadLibraryA("ucrtbase.dll"); + if(!ucrtbase) + { + win_skip("ucrtbase.dll not installed\n"); + FreeLibrary(msvcp); + return FALSE; + } + + SET(msvcp, p__Aligned_new_delete_resource, "_Aligned_new_delete_resource"); + SET(msvcp, p__Unaligned_new_delete_resource, "_Unaligned_new_delete_resource"); + SET(msvcp, p_null_memory_resource, "null_memory_resource"); + SET(msvcp, p__Aligned_get_default_resource, "_Aligned_get_default_resource"); + SET(msvcp, p__Unaligned_get_default_resource, "_Unaligned_get_default_resource"); + SET(msvcp, p__Aligned_set_default_resource, "_Aligned_set_default_resource"); + SET(msvcp, p__Unaligned_set_default_resource, "_Unaligned_set_default_resource"); + + SET(ucrtbase, p__aligned_malloc, "_aligned_malloc"); + SET(ucrtbase, p__aligned_free, "_aligned_free"); + SET(ucrtbase, p_malloc, "malloc"); + SET(ucrtbase, p_free, "free"); + + init_thiscall_thunk(); + + return TRUE; +} + +static void test__Aligned_new_delete_resource(void) +{ + void *ptr; + memory_resource *resource = p__Aligned_new_delete_resource(); + ok(resource != NULL, "Failed to get aligned new delete memory resource.\n"); + + /* calling dtor should be harmless nop */ + call_func1(resource->vtbl->dtor, resource); + + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, 32); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, 32); + + /* up to the alignment of 16 it is using non-aligned new/delete */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, 16); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + p_free(ptr); /* aligned delete, crashes with non-aligned */ + + ptr = p_malloc(140); + ok(ptr != NULL, "Failed to allocate memory using malloc.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, 8); + + /* past the alignment of 16 it is using aligned new/delete */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, 32); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + p__aligned_free(ptr); /* aligned delete, crashes with non-aligned */ + + ptr = p__aligned_malloc(140, 32); + ok(ptr != NULL, "Failed to allocate memory using _aligned_malloc.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, 32); + + ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource), "Expected resource to be equal to itself.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL), "Expected resource to not be equal to NULL.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1), "Expected resource to not be equal to a random pointer.\n"); +} + +static void test__Unaligned_new_delete_resource(void) +{ + void *ptr; + memory_resource *resource = p__Unaligned_new_delete_resource(); + ok(resource != NULL, "Failed to get unaligned new delete memory resource.\n"); + + /* calling dtor should be a harmless nop */ + call_func1(resource->vtbl->dtor, resource); + + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, MAX_UNALIGNED_ALIGNMENT); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, MAX_UNALIGNED_ALIGNMENT); + + /* up to the alignment of 16 it is using non-aligned new/delete */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, 8); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + p_free(ptr); /* aligned delete */ + + ptr = p_malloc(140); + ok(ptr != NULL, "Failed to allocate memory using malloc.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, 2); + + /* alignment past MAX_UNALIGNED_ALIGNMENT results in bad alloc exception */ + /* ptr = call_func3(resource->vtbl->do_allocate, resource, 140, MAX_UNALIGNED_ALIGNMENT*2); */ + + ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource), "Expected resource to be equal to itself.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL), "Expected resource to not be equal to NULL.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1), "Expected resource to not be equal to a random pointer.\n"); +} + +static void test_null_memory_resource(void) +{ + memory_resource *resource = p_null_memory_resource(); + ok(resource != NULL, "Failed to get null memory resource.\n"); + + /* should result in bad alloc exception */ + /* call_func3(resource->vtbl->do_allocate, resource, 140, 8); */ + + /* harmless nop */ + call_func4(resource->vtbl->do_deallocate, resource, (void*)(INT_PTR)-1, 140, 2); + + ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource), "Expected resource to be equal to itself.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL), "Expected resource to not be equal to NULL.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1), "Expected resource to not be equal to a random pointer.\n"); +} + +static void test_get_set_defult_resource(memory_resource *(__cdecl *new_delete_resource)(void), + memory_resource *(__cdecl *get_default_resource)(void), + memory_resource *(__cdecl *set_default_resource)(memory_resource *resource)) +{ + memory_resource *new_resource = new_delete_resource(); + memory_resource *default_resource = get_default_resource(); + ok(default_resource == new_resource, "Expected the default memory resource to be equal new/delete one.\n"); + + default_resource = set_default_resource((void*)0xdeadbeef); + ok(default_resource == new_resource, "Expected that setting default resource would return the old one.\n"); + + default_resource = get_default_resource(); + ok(default_resource == (void*)0xdeadbeef, "Expected that setting reasource would take effect.\n"); + + default_resource = set_default_resource(NULL); + ok(default_resource == (void*)0xdeadbeef, "Expected that setting default resource would return the old one.\n"); + + default_resource = get_default_resource(); + ok(default_resource == new_resource, "Expected that setting default resource to NULL would reset the value.\n"); +} + +START_TEST(msvcp140_1) +{ + if (!init()) return; + + test__Aligned_new_delete_resource(); + test__Unaligned_new_delete_resource(); + + test_null_memory_resource(); + + test_get_set_defult_resource(p__Aligned_new_delete_resource, p__Aligned_get_default_resource, p__Aligned_set_default_resource); + test_get_set_defult_resource(p__Unaligned_new_delete_resource, p__Unaligned_get_default_resource, p__Unaligned_set_default_resource); + + FreeLibrary(msvcp); + FreeLibrary(ucrtbase); +}
Hi Arek,
I still need to look more into first patch so you can wait with resend. Here are some initial comments:
On 4/1/21 3:38 PM, Arkadiusz Hiler wrote:
+#ifdef __i386__ +#define MAX_UNALIGNED_ALIGNMENT 8 +#else +#define MAX_UNALIGNED_ALIGNMENT 16 +#endif
It probably corresponds to operator new alignment. If so it would make more sense to define it as: #define NEW_ALIGNMENT (2*sizeof(void*)) so it matches with new alignment on arm.
+DEFINE_RTTI_DATA0(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") +DEFINE_RTTI_DATA1(aligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Aligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(unaligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Unligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(null_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_null_resource@pmr@std@@")
This doesn't match with native RTTI data. If you need help with that part please let me know
+DEFINE_THISCALL_WRAPPER(aligned_do_allocate, 12) +void* __thiscall aligned_do_allocate(memory_resource *this, size_t bytes, size_t alignment) +{
- return MSVCRT_operator_new_aligned(bytes, alignment);
+}
This doesn't match the tests that are calling free (instead of _aligned_free) in some cases.
+DEFINE_THISCALL_WRAPPER(aligned_do_deallocate, 16) +void __thiscall aligned_do_deallocate(memory_resource *this, void *p, size_t bytes, size_t alignment) +{
- MSVCRT_operator_delete_aligned(p, alignment);
+}
Same here.
+static memory_resource impl_aligned_resource = { &MSVCP_aligned_resource_vtable }; +static memory_resource impl_unaligned_resource = { &MSVCP_unaligned_resource_vtable }; +static memory_resource impl_null_resource = { &MSVCP_null_resource_vtable };
+memory_resource *default_unaligned_resource = &impl_unaligned_resource; +memory_resource *default_aligned_resource = &impl_aligned_resource;
Quick test shows that _Aligned_get_default_resource and _Unaligned_get_default_resource returns the same data after _Aligned_set_default_resource(0xdeadbeef) call. Probably there's only one default_resource variable that is shared in both of the functions. It should probably return default object when set to NULL and stored object otherwise. I'm thinking about something like: memory_resource* __cdecl _Aligned_new_delete_resource(void) { static memory_resource impl_aligned_resource = { &MSVCP_aligned_resource_vtable }; return &impl_aligned_resource; }
memory_resource* __cdecl _Aligned_get_default_resource(void) { if (default_resource) return default_resource; return _Aligned_new_delete_resource(); }
memory_resource* __cdecl _Aligned_set_default_resource(memory_resource *res) { memory_resource *ret = InterlockedExchangePointer((void**)&default_resource, res); if (!ret) ret = _Aligned_new_delete_resource(); return ret; }
+static void init_cxx_funcs(void) +{
- msvcp140 = LoadLibraryA("msvcp140.dll");
- if (!msvcp140) FIXME("Failed to load msvcp140.dll\n");
- throw_bad_alloc = (void*)GetProcAddress(msvcp140, "?_Xbad_alloc@std@@YAXXZ");
- if (!throw_bad_alloc) FIXME("Failed to get address of ?_Xbad_alloc@std@@YAXXZ\n");
+}
Please return error (so dll fails to load) if msvcp140 can't be loaded.
+static void test__Aligned_new_delete_resource(void) +{
- void *ptr;
- memory_resource *resource = p__Aligned_new_delete_resource();
- ok(resource != NULL, "Failed to get aligned new delete memory resource.\n");
- /* calling dtor should be harmless nop */
- call_func1(resource->vtbl->dtor, resource);
Please avoid adding such tests (or add them as last test in the file). Sometimes it changes object behavior in unexpected ways. I guess that in this case it should work but it's better to play safe.
- p_free(ptr); /* aligned delete, crashes with non-aligned */
Looks like the comment was copied from _aligned_free case.
+static void test_get_set_defult_resource(memory_resource *(__cdecl *new_delete_resource)(void),
memory_resource *(__cdecl *get_default_resource)(void),
memory_resource *(__cdecl *set_default_resource)(memory_resource *resource))
+{
- memory_resource *new_resource = new_delete_resource();
- memory_resource *default_resource = get_default_resource();
- ok(default_resource == new_resource, "Expected the default memory resource to be equal new/delete one.\n");
- default_resource = set_default_resource((void*)0xdeadbeef);
- ok(default_resource == new_resource, "Expected that setting default resource would return the old one.\n");
- default_resource = get_default_resource();
- ok(default_resource == (void*)0xdeadbeef, "Expected that setting reasource would take effect.\n");
- default_resource = set_default_resource(NULL);
- ok(default_resource == (void*)0xdeadbeef, "Expected that setting default resource would return the old one.\n");
- default_resource = get_default_resource();
- ok(default_resource == new_resource, "Expected that setting default resource to NULL would reset the value.\n");
+}
Please add a test that calls p__Unaligned_get_default_resource after p__Aligned_set_default_resource(0xdeadbeef) call.
Thanks, Piotr
On Fri, Apr 02, 2021 at 06:18:28PM +0200, Piotr Caban wrote:
+DEFINE_RTTI_DATA0(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") +DEFINE_RTTI_DATA1(aligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Aligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(unaligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Unligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(null_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_null_resource@pmr@std@@")
This doesn't match with native RTTI data. If you need help with that part please let me know
Those names should be correct:
.?AVmemory_resource@pmr@std@@ .?AV_Aligned_new_delete_resource_impl@pmr@std@@ .?AV_Unaligned_new_delete_resource_impl@pmr@std@@ .?AV_Null_resource@?1??null_memory_resource@@YAPAVmemory_resource@pmr@std@@XZ@
Is there anything else wrong with this RTTI?
+DEFINE_RTTI_DATA0(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") +DEFINE_RTTI_DATA1(aligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Aligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(unaligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Unligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(null_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_null_resource@pmr@std@@")
+DEFINE_THISCALL_WRAPPER(aligned_do_allocate, 12) +void* __thiscall aligned_do_allocate(memory_resource *this, size_t bytes, size_t alignment) +{
- return MSVCRT_operator_new_aligned(bytes, alignment);
+}
This doesn't match the tests that are calling free (instead of _aligned_free) in some cases.
+DEFINE_THISCALL_WRAPPER(aligned_do_deallocate, 16) +void __thiscall aligned_do_deallocate(memory_resource *this, void *p, size_t bytes, size_t alignment) +{
- MSVCRT_operator_delete_aligned(p, alignment);
+}
Same here.
Ah yes. I've tweaked the tests to not crash on Windows, but forgot to change our impl. The tests are passing because our malloc()/free() and its aligned siblings are compatible wrt how they store the address of the original allocation making them interchangeable, so this was left unnoticed.
Now... thinking about it, it probably should use NEW_ALIGNMENT.
I'll add explicit tests for NEW_ALIGNMENT and 2 * NEW_ALIGNMENT to be 100% sure.
ACK on all the other comments and thanks for the review! :-)
Do you want me to send this and your version of patch 1 together or are you going to upstream it on your own?
On 4/5/21 6:36 PM, Arkadiusz Hiler wrote:
On Fri, Apr 02, 2021 at 06:18:28PM +0200, Piotr Caban wrote:
+DEFINE_RTTI_DATA0(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") +DEFINE_RTTI_DATA1(aligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Aligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(unaligned_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Unligned_new_delete_resource@pmr@std@@") +DEFINE_RTTI_DATA1(null_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_null_resource@pmr@std@@")
This doesn't match with native RTTI data. If you need help with that part please let me know
Those names should be correct:
.?AVmemory_resource@pmr@std@@ .?AV_Aligned_new_delete_resource_impl@pmr@std@@ .?AV_Unaligned_new_delete_resource_impl@pmr@std@@ .?AV_Null_resource@?1??null_memory_resource@@YAPAVmemory_resource@pmr@std@@XZ@
Is there anything else wrong with this RTTI?
The aligned_resource, unaligned_resource and null_resource are also inheriting '.?AV_Identity_equal_resource@pmr@std@@' class.
The definitions should look like this: DEFINE_RTTI_DATA0(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") DEFINE_RTTI_DATA1(_Identity_equal_resource, 0, &base_memory_resource_rtti_base_descriptor, ".?AV_Identity_equal_resource@pmr@std@@") DEFINE_RTTI_DATA2(aligned_resource, 0, &_Identity_equal_resource_rtti_base_descriptor, &base_memory_resource_rtti_base_descriptor, ".?AV_Aligned_new_delete_resource_impl@pmr@std@@")
Another problem is that DEFINE_RTTI_DATA defines lots of unused structures in case of base_memory_resource and _Identity_equal_resource classes (e.g. virtual function tables should not be needed at all). I will experiment with it tomorrow.
+DEFINE_THISCALL_WRAPPER(aligned_do_allocate, 12) +void* __thiscall aligned_do_allocate(memory_resource *this, size_t bytes, size_t alignment) +{
- return MSVCRT_operator_new_aligned(bytes, alignment);
+}
This doesn't match the tests that are calling free (instead of _aligned_free) in some cases.
+DEFINE_THISCALL_WRAPPER(aligned_do_deallocate, 16) +void __thiscall aligned_do_deallocate(memory_resource *this, void *p, size_t bytes, size_t alignment) +{
- MSVCRT_operator_delete_aligned(p, alignment);
+}
Same here.
Ah yes. I've tweaked the tests to not crash on Windows, but forgot to change our impl. The tests are passing because our malloc()/free() and its aligned siblings are compatible wrt how they store the address of the original allocation making them interchangeable, so this was left unnoticed.
It probably fails to free the memory if it's used interchangeable.
Do you want me to send this and your version of patch 1 together or are you going to upstream it on your own?
Please send it together with your patches.
Thanks, Piotr
Hi Arek,
I'm attaching a patch generated on top of the patches you have sent to wine that adds DEFINE_RTTI_BASE helper and uses it in msvcp140_1. It also removes unused vtable definition.
Thanks, Piotr
Hi Arek,
I'm attaching alternative solution for type_info_vtable definition. I think it makes sense to make the cxx.h file independent from other files. What do you think about it?
Thanks, Piotr
On Fri, Apr 02, 2021 at 10:39:59PM +0200, Piotr Caban wrote:
Hi Arek,
I'm attaching alternative solution for type_info_vtable definition. I think it makes sense to make the cxx.h file independent from other files. What do you think about it?
Thanks, Piotr
From ac91f5f1dd440cfdb43c9ae346e7bfd7b78629d9 Mon Sep 17 00:00:00 2001 From: Piotr Caban piotr@codeweavers.com Date: Fri, 2 Apr 2021 22:31:19 +0200 Subject: [PATCH] msvcp90: Define type_info vtable in cxx.h header if requested. To: wine-devel wine-devel@winehq.org
dlls/msvcp90/cxx.h | 33 +++++++++++++++++++++++++++++++++ dlls/msvcp90/exception.c | 31 +------------------------------ 2 files changed, 34 insertions(+), 30 deletions(-)
diff --git a/dlls/msvcp90/cxx.h b/dlls/msvcp90/cxx.h index 7af11de7fe6..43b8df61012 100644 --- a/dlls/msvcp90/cxx.h +++ b/dlls/msvcp90/cxx.h @@ -452,3 +452,36 @@ typedef struct } cxx_exception_type;
#endif
+#ifdef DEFINE_TYPE_INFO +static void MSVCP_type_info_dtor(type_info * _this) +{
- free(_this->name);
+}
+DEFINE_THISCALL_WRAPPER(MSVCP_type_info_vector_dtor,8) +void * __thiscall MSVCP_type_info_vector_dtor(type_info * _this, unsigned int flags) +{
- if (flags & 2)
- {
/* we have an array, with the number of elements stored before the first object */
INT_PTR i, *ptr = (INT_PTR *)_this - 1;
for (i = *ptr - 1; i >= 0; i--) MSVCP_type_info_dtor(_this + i);
free(ptr);
- }
- else
- {
MSVCP_type_info_dtor(_this);
if (flags & 1) free(_this);
- }
- return _this;
+}
+DEFINE_RTTI_DATA0( type_info, 0, ".?AVtype_info@@" )
+__ASM_BLOCK_BEGIN(type_info_vtables)
- __ASM_VTABLE(type_info,
VTABLE_ADD_FUNC(MSVCP_type_info_vector_dtor));
+__ASM_BLOCK_END +#endif
I was considering something similar at first, but I didn't like the idea of having RTTI/dtor definitions behind an ifdef in a header file.
I don't have a strong preference though so if this is fine with you then it's also fine with me.
On 4/5/21 4:00 PM, Arkadiusz Hiler wrote:
I was considering something similar at first, but I didn't like the idea of having RTTI/dtor definitions behind an ifdef in a header file.
I don't have a strong preference though so if this is fine with you then it's also fine with me.
I don't like any of this solutions but I don't see how it can be improved without compiler support. Since the cxx.h file is shared between msvcp and msvcrt I think it makes sense to make the file independent of other source files.
Thanks, Piotr