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
26 #include "wine/test.h"
27 #include "wine/exception.h"
30 typedef unsigned char MSVCP_bool
;
34 #define __thiscall __stdcall
36 #define __thiscall __cdecl
39 #define NEW_ALIGNMENT (2*sizeof(void*))
41 /* Emulate __thiscall */
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 */
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))
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)
94 struct memory_resource_vtbl
;
97 struct memory_resource_vtbl
*vtbl
;
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");
134 win_skip("msvcp140_1.dll not installed\n");
138 ucrtbase
= LoadLibraryA("ucrtbase.dll");
141 win_skip("ucrtbase.dll not installed\n");
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();
164 static void test__Aligned_new_delete_resource(void)
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 */
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)
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 */
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); */
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
)
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
);
304 FreeLibrary(ucrtbase
);