diff --git a/configure b/configure index 4665a6f5876..9eee07f8876 100755 --- a/configure +++ b/configure @@ -20827,6 +20827,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 2217330d60e..2f5a6987a13 100644 --- a/configure.ac +++ b/configure.ac @@ -3501,6 +3501,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..6b87bdb8018 100644 --- a/dlls/msvcp140_1/Makefile.in +++ b/dlls/msvcp140_1/Makefile.in @@ -1 +1,6 @@ -MODULE = msvcp140_1.dll +MODULE = msvcp140_1.dll +PARENTSRC = ../msvcp90 + +EXTRADLLFLAGS = -mno-cygwin + +C_SRCS = 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..c74420bf3d0 --- /dev/null +++ b/dlls/msvcp140_1/msvcp140_1.c @@ -0,0 +1,290 @@ +/* + * 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 +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "winnls.h" +#include "cxx.h" + +#define NEW_ALIGNMENT (2*sizeof(void*)) + +WINE_DEFAULT_DEBUG_CHANNEL(msvcp); + +CREATE_TYPE_INFO_VTABLE + +static HMODULE msvcp140; + +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(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_BASE(base_memory_resource, 0, ".?AVmemory_resource@pmr@std@@") +DEFINE_RTTI_BASE(_Identity_equal_resource, 0, ".?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@@") +DEFINE_RTTI_DATA2(unaligned_resource, 0, &_Identity_equal_resource_rtti_base_descriptor, + &base_memory_resource_rtti_base_descriptor, + ".?AV_Unaligned_new_delete_resource_impl@pmr@std@@") +DEFINE_RTTI_DATA2(null_resource, 0, &_Identity_equal_resource_rtti_base_descriptor, + &base_memory_resource_rtti_base_descriptor, + ".?AV_Null_resource@?1??null_memory_resource@@YAPAVmemory_resource@pmr@std@@XZ") + +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) +{ + if (alignment > NEW_ALIGNMENT) + return MSVCRT_operator_new_aligned(bytes, alignment); + else + return MSVCRT_operator_new(bytes); +} + +DEFINE_THISCALL_WRAPPER(aligned_do_deallocate, 16) +void __thiscall aligned_do_deallocate(memory_resource *this, + void *p, size_t bytes, size_t alignment) +{ + if (alignment > NEW_ALIGNMENT) + MSVCRT_operator_delete_aligned(p, alignment); + else + MSVCRT_operator_delete(p); +} + +DEFINE_THISCALL_WRAPPER(unaligned_do_allocate, 12) +void* __thiscall unaligned_do_allocate(memory_resource *this, + size_t bytes, size_t alignment) +{ + if (alignment > NEW_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 *default_resource; + +/* EXPORTS */ + +memory_resource* __cdecl _Aligned_new_delete_resource(void) +{ + static memory_resource impl = { &MSVCP_aligned_resource_vtable }; + return &impl; +} + +memory_resource* __cdecl _Unaligned_new_delete_resource(void) +{ + static memory_resource impl = { &MSVCP_unaligned_resource_vtable }; + return &impl; +} + +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; +} + +memory_resource* __cdecl _Unaligned_get_default_resource(void) +{ + if (default_resource) return default_resource; + return _Unaligned_new_delete_resource(); +} + +memory_resource* __cdecl _Unaligned_set_default_resource(memory_resource *res) +{ + memory_resource *ret = InterlockedExchangePointer((void**)&default_resource, res); + if (!ret) ret = _Unaligned_new_delete_resource(); + return ret; +} + +memory_resource* __cdecl null_memory_resource(void) +{ + static memory_resource impl = { &MSVCP_null_resource_vtable }; + return &impl; +} + +/* DLL INIT */ + +static BOOL init_cxx_funcs(void) +{ + msvcp140 = LoadLibraryA("msvcp140.dll"); + if (!msvcp140) + { + FIXME("Failed to load msvcp140.dll\n"); + return FALSE; + } + + 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"); + FreeLibrary(msvcp140); + return FALSE; + } + + return TRUE; +} + +static void init_rtti(void *base) +{ +#ifdef __x86_64__ + init_type_info_rtti(base); + init_base_memory_resource_rtti(base); + init__Identity_equal_resource_rtti(base); + init_aligned_resource_rtti(base); + init_unaligned_resource_rtti(base); + init_null_resource_rtti(base); +#endif +} + +BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + if (!init_cxx_funcs()) return FALSE; + init_rtti(inst); + break; + case DLL_PROCESS_DETACH: + if (reserved) break; + 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..a773e4a236c --- /dev/null +++ b/dlls/msvcp140_1/tests/msvcp140_1.c @@ -0,0 +1,305 @@ +/* + * 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 +#include + +#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 + +#define NEW_ALIGNMENT (2*sizeof(void*)) + +/* 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)(memory_resource *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*); +static memory_resource* (__cdecl *p__Unaligned_set_default_resource)(memory_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"); + + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, 64); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, 64); + + /* up to the NEW_ALIGNMENT it should use the non-aligned new/delete */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + p_free(ptr); /* delete, crashes with aligned */ + + ptr = p_malloc(140); + ok(ptr != NULL, "Failed to allocate memory using _aligned_malloc.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT); + + /* past the NEW_ALIGNMENT it should use the aligned new/delete */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT * 2); + 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, NEW_ALIGNMENT * 2); + ok(ptr != NULL, "Failed to allocate memory using _aligned_malloc.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT * 2); + + /* until the NEW_ALIGNMENT it doesn't have to be a power of two */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT - 1); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT - 1); + + /* crashes with alignment not being a power of two past the NEW_ALIGNMENT */ + /* ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT * 2 + 1); */ + + ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource), + "Resource should be equal to itself.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL), + "Resource should not be equal to NULL.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1), + "Resource should 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"); + + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT); + + /* up to the NEW_ALIGNMENT it is using non-aligned new/delete */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + p_free(ptr); /* delete */ + + /* alignment doesn't have to be a power of two */ + ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT - 1); + ok(ptr != NULL, "Failed to allocate memory using memory resource.\n"); + p_free(ptr); /* delete */ + + ptr = p_malloc(140); + ok(ptr != NULL, "Failed to allocate memory using malloc.\n"); + call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT); + + /* alignment past NEW_ALIGNMENT results in bad alloc exception */ + /* ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT * 2); */ + + ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource), + "Resource should be equal to itself.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL), + "Resource should not be equal to NULL.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1), + "Resource should 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), + "Resource should be equal to itself.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL), + "Resource should not be equal to NULL.\n"); + ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1), + "Resource should 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 *set_default_resource)(memory_resource*)) +{ + ok(p__Unaligned_get_default_resource() == p__Unaligned_new_delete_resource(), + "The default aligned resource should be equal to new/delete one.\n"); + ok(p__Aligned_get_default_resource() == p__Aligned_new_delete_resource(), + "The default unaligned resource should be equal to new/delete one.\n"); + + ok(set_default_resource((void*)0xdeadbeef) == new_delete_resource(), + "Setting default resource should return the old one.\n"); + + /* the value is shared */ + ok(p__Unaligned_get_default_resource() == (void*)0xdeadbeef, + "Setting resource should change the default unaligned resource.\n"); + ok(p__Aligned_get_default_resource() == (void*)0xdeadbeef, + "Setting resource should change the default aligned resource.\n"); + + ok(set_default_resource(NULL) == (void*)0xdeadbeef, + "Setting default resource should return the old one.\n"); + + ok(p__Unaligned_get_default_resource() == p__Unaligned_new_delete_resource(), + "Setting the default resource to NULL should reset the unaligned default.\n"); + ok(p__Aligned_get_default_resource() == p__Aligned_new_delete_resource(), + "Setting the default resource to NULL should reset the aligned default.\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_set_default_resource); + test_get_set_defult_resource(p__Unaligned_new_delete_resource, + p__Unaligned_set_default_resource); + + FreeLibrary(msvcp); + FreeLibrary(ucrtbase); +}