msvcp140_1: Implement the DLL.
[wine.git] / dlls / msvcp140_1 / tests / msvcp140_1.c
bloba773e4a236cf10b55db8ba94f4537503ae0c499d
1 /*
2 * Copyright 2021 Arkadiusz Hiler for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <errno.h>
20 #include <stdio.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
26 #include "wine/test.h"
27 #include "wine/exception.h"
28 #include "winbase.h"
30 typedef unsigned char MSVCP_bool;
32 #undef __thiscall
33 #ifdef __i386__
34 #define __thiscall __stdcall
35 #else
36 #define __thiscall __cdecl
37 #endif
39 #define NEW_ALIGNMENT (2*sizeof(void*))
41 /* Emulate __thiscall */
42 #ifdef __i386__
44 #include "pshpack1.h"
45 struct thiscall_thunk
47 BYTE pop_eax; /* popl %eax (ret addr) */
48 BYTE pop_edx; /* popl %edx (func) */
49 BYTE pop_ecx; /* popl %ecx (this) */
50 BYTE push_eax; /* pushl %eax */
51 WORD jmp_edx; /* jmp *%edx */
53 #include "poppack.h"
55 static void* (WINAPI *call_thiscall_func1)(void *func, void *this);
56 static void* (WINAPI *call_thiscall_func2)(void *func, void *this, const void *a);
57 static void* (WINAPI *call_thiscall_func3)(void *func,
58 void *this, const void *a, const void *b);
59 static void* (WINAPI *call_thiscall_func4)(void *func,
60 void *this, const void *a, const void *b, const void *c);
62 static void init_thiscall_thunk(void)
64 struct thiscall_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk),
65 MEM_COMMIT, PAGE_EXECUTE_READWRITE);
66 thunk->pop_eax = 0x58; /* popl %eax */
67 thunk->pop_edx = 0x5a; /* popl %edx */
68 thunk->pop_ecx = 0x59; /* popl %ecx */
69 thunk->push_eax = 0x50; /* pushl %eax */
70 thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
71 call_thiscall_func1 = (void*)thunk;
72 call_thiscall_func2 = (void*)thunk;
73 call_thiscall_func3 = (void*)thunk;
74 call_thiscall_func4 = (void*)thunk;
77 #define call_func1(func,_this) call_thiscall_func1(func,_this)
78 #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a))
79 #define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,\
80 (const void*)(a),(const void*)(b))
81 #define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,\
82 (const void*)(a),(const void*)(b), (const void*)(c))
84 #else
86 #define init_thiscall_thunk()
87 #define call_func1(func,_this) func(_this)
88 #define call_func2(func,_this,a) func(_this,a)
89 #define call_func3(func,_this,a,b) func(_this,a,b)
90 #define call_func4(func,_this,a,b,c) func(_this,a,b,c)
92 #endif /* __i386__ */
94 struct memory_resource_vtbl;
96 typedef struct {
97 struct memory_resource_vtbl *vtbl;
98 } memory_resource;
100 struct memory_resource_vtbl
102 void (__thiscall *dtor)(memory_resource *this);
103 void* (__thiscall *do_allocate)(memory_resource *this,
104 size_t bytes, size_t alignment);
105 void (__thiscall *do_deallocate)(memory_resource *this,
106 void *p, size_t bytes, size_t alignment);
107 MSVCP_bool (__thiscall *do_is_equal)(memory_resource *this,
108 memory_resource *other);
111 static HMODULE msvcp;
112 static memory_resource* (__cdecl *p__Aligned_new_delete_resource)(void);
113 static memory_resource* (__cdecl *p__Unaligned_new_delete_resource)(void);
114 static memory_resource* (__cdecl *p__Aligned_get_default_resource)(void);
115 static memory_resource* (__cdecl *p__Unaligned_get_default_resource)(void);
116 static memory_resource* (__cdecl *p__Aligned_set_default_resource)(memory_resource*);
117 static memory_resource* (__cdecl *p__Unaligned_set_default_resource)(memory_resource*);
118 static memory_resource* (__cdecl *p_null_memory_resource)(void);
120 static HMODULE ucrtbase;
121 static void* (__cdecl *p_malloc)(size_t size);
122 static void (__cdecl *p_free)(void *ptr);
123 static void* (__cdecl *p__aligned_malloc)(size_t size, size_t alignment);
124 static void (__cdecl *p__aligned_free)(void *ptr);
126 #define SETNOFAIL(lib,x,y) x = (void*)GetProcAddress(lib,y)
127 #define SET(lib,x,y) do { SETNOFAIL(lib,x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
129 static BOOL init(void)
131 msvcp = LoadLibraryA("msvcp140_1.dll");
132 if(!msvcp)
134 win_skip("msvcp140_1.dll not installed\n");
135 return FALSE;
138 ucrtbase = LoadLibraryA("ucrtbase.dll");
139 if(!ucrtbase)
141 win_skip("ucrtbase.dll not installed\n");
142 FreeLibrary(msvcp);
143 return FALSE;
146 SET(msvcp, p__Aligned_new_delete_resource, "_Aligned_new_delete_resource");
147 SET(msvcp, p__Unaligned_new_delete_resource, "_Unaligned_new_delete_resource");
148 SET(msvcp, p_null_memory_resource, "null_memory_resource");
149 SET(msvcp, p__Aligned_get_default_resource, "_Aligned_get_default_resource");
150 SET(msvcp, p__Unaligned_get_default_resource, "_Unaligned_get_default_resource");
151 SET(msvcp, p__Aligned_set_default_resource, "_Aligned_set_default_resource");
152 SET(msvcp, p__Unaligned_set_default_resource, "_Unaligned_set_default_resource");
154 SET(ucrtbase, p__aligned_malloc, "_aligned_malloc");
155 SET(ucrtbase, p__aligned_free, "_aligned_free");
156 SET(ucrtbase, p_malloc, "malloc");
157 SET(ucrtbase, p_free, "free");
159 init_thiscall_thunk();
161 return TRUE;
164 static void test__Aligned_new_delete_resource(void)
166 void *ptr;
167 memory_resource *resource = p__Aligned_new_delete_resource();
168 ok(resource != NULL, "Failed to get aligned new delete memory resource.\n");
170 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, 64);
171 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
172 call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, 64);
174 /* up to the NEW_ALIGNMENT it should use the non-aligned new/delete */
175 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT);
176 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
177 p_free(ptr); /* delete, crashes with aligned */
179 ptr = p_malloc(140);
180 ok(ptr != NULL, "Failed to allocate memory using _aligned_malloc.\n");
181 call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT);
183 /* past the NEW_ALIGNMENT it should use the aligned new/delete */
184 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT * 2);
185 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
186 p__aligned_free(ptr); /* aligned delete, crashes with non-aligned */
188 ptr = p__aligned_malloc(140, NEW_ALIGNMENT * 2);
189 ok(ptr != NULL, "Failed to allocate memory using _aligned_malloc.\n");
190 call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT * 2);
192 /* until the NEW_ALIGNMENT it doesn't have to be a power of two */
193 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT - 1);
194 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
195 call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT - 1);
197 /* crashes with alignment not being a power of two past the NEW_ALIGNMENT */
198 /* ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT * 2 + 1); */
200 ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource),
201 "Resource should be equal to itself.\n");
202 ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL),
203 "Resource should not be equal to NULL.\n");
204 ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1),
205 "Resource should not be equal to a random pointer.\n");
208 static void test__Unaligned_new_delete_resource(void)
210 void *ptr;
211 memory_resource *resource = p__Unaligned_new_delete_resource();
212 ok(resource != NULL, "Failed to get unaligned new delete memory resource.\n");
214 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT);
215 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
216 call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT);
218 /* up to the NEW_ALIGNMENT it is using non-aligned new/delete */
219 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT);
220 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
221 p_free(ptr); /* delete */
223 /* alignment doesn't have to be a power of two */
224 ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT - 1);
225 ok(ptr != NULL, "Failed to allocate memory using memory resource.\n");
226 p_free(ptr); /* delete */
228 ptr = p_malloc(140);
229 ok(ptr != NULL, "Failed to allocate memory using malloc.\n");
230 call_func4(resource->vtbl->do_deallocate, resource, ptr, 140, NEW_ALIGNMENT);
232 /* alignment past NEW_ALIGNMENT results in bad alloc exception */
233 /* ptr = call_func3(resource->vtbl->do_allocate, resource, 140, NEW_ALIGNMENT * 2); */
235 ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource),
236 "Resource should be equal to itself.\n");
237 ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL),
238 "Resource should not be equal to NULL.\n");
239 ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1),
240 "Resource should not be equal to a random pointer.\n");
243 static void test_null_memory_resource(void)
245 memory_resource *resource = p_null_memory_resource();
246 ok(resource != NULL, "Failed to get null memory resource.\n");
248 /* should result in bad alloc exception */
249 /* call_func3(resource->vtbl->do_allocate, resource, 140, 8); */
251 /* harmless nop */
252 call_func4(resource->vtbl->do_deallocate, resource, (void*)(INT_PTR)-1, 140, 2);
254 ok((MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource),
255 "Resource should be equal to itself.\n");
256 ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, NULL),
257 "Resource should not be equal to NULL.\n");
258 ok(!(MSVCP_bool)(INT_PTR)call_func2(resource->vtbl->do_is_equal, resource, resource+1),
259 "Resource should not be equal to a random pointer.\n");
262 static void test_get_set_defult_resource(
263 memory_resource *(__cdecl *new_delete_resource)(void),
264 memory_resource *(__cdecl *set_default_resource)(memory_resource*))
266 ok(p__Unaligned_get_default_resource() == p__Unaligned_new_delete_resource(),
267 "The default aligned resource should be equal to new/delete one.\n");
268 ok(p__Aligned_get_default_resource() == p__Aligned_new_delete_resource(),
269 "The default unaligned resource should be equal to new/delete one.\n");
271 ok(set_default_resource((void*)0xdeadbeef) == new_delete_resource(),
272 "Setting default resource should return the old one.\n");
274 /* the value is shared */
275 ok(p__Unaligned_get_default_resource() == (void*)0xdeadbeef,
276 "Setting resource should change the default unaligned resource.\n");
277 ok(p__Aligned_get_default_resource() == (void*)0xdeadbeef,
278 "Setting resource should change the default aligned resource.\n");
280 ok(set_default_resource(NULL) == (void*)0xdeadbeef,
281 "Setting default resource should return the old one.\n");
283 ok(p__Unaligned_get_default_resource() == p__Unaligned_new_delete_resource(),
284 "Setting the default resource to NULL should reset the unaligned default.\n");
285 ok(p__Aligned_get_default_resource() == p__Aligned_new_delete_resource(),
286 "Setting the default resource to NULL should reset the aligned default.\n");
289 START_TEST(msvcp140_1)
291 if (!init()) return;
293 test__Aligned_new_delete_resource();
294 test__Unaligned_new_delete_resource();
296 test_null_memory_resource();
298 test_get_set_defult_resource(p__Aligned_new_delete_resource,
299 p__Aligned_set_default_resource);
300 test_get_set_defult_resource(p__Unaligned_new_delete_resource,
301 p__Unaligned_set_default_resource);
303 FreeLibrary(msvcp);
304 FreeLibrary(ucrtbase);