1 /*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Test for RtlMultipleAllocateHeap and RtlMultipleFreeHeap
5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6 */
7 #include "precomp.h"
8
9 #include <pseh/pseh2.h>
10
11 typedef ULONG (NTAPI *FN_RtlMultipleAllocateHeap)(IN PVOID, IN ULONG, IN SIZE_T, IN ULONG, OUT PVOID *);
12 typedef ULONG (NTAPI *FN_RtlMultipleFreeHeap)(IN PVOID, IN ULONG, IN ULONG, OUT PVOID *);
13
14 static FN_RtlMultipleAllocateHeap g_alloc = NULL;
15 static FN_RtlMultipleFreeHeap g_free = NULL;
16
17 #define TEST_ALLOC(ret_expected,err_expected,threw_excepted,HeapHandle,Flags,Size,Count,Array) \
18 threw = 0; \
19 SetLastError(-1); \
20 _SEH2_TRY { \
21 ret = g_alloc((HeapHandle), (Flags), (Size), (Count), (Array)); \
22 err = GetLastError(); \
23 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
24 threw = _SEH2_GetExceptionCode(); \
25 } \
26 _SEH2_END; \
27 ok((ret) == (ret_expected), "ret excepted %d, but %d\n", (ret_expected), (ret)); \
28 ok((err) == (err_expected), "err excepted %d, but %d\n", (err_expected), (err)); \
29 ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", (threw_excepted), (threw));
30
31 #define TEST_ALLOC_NO_RET(err_expected,threw_excepted,HeapHandle,Flags,Size,Count,Array) \
32 threw = 0; \
33 SetLastError(-1); \
34 _SEH2_TRY { \
35 ret = g_alloc((HeapHandle), (Flags), (Size), (Count), (Array)); \
36 err = GetLastError(); \
37 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
38 threw = _SEH2_GetExceptionCode(); \
39 } \
40 _SEH2_END; \
41 ok((err) == (err_expected), "err excepted %d, but %d", (err_expected), (err)); \
42 ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", (threw_excepted), (threw));
43
44 #define TEST_FREE(ret_expected,err_expected,threw_excepted,HeapHandle,Flags,Count,Array) \
45 threw = 0; \
46 SetLastError(-1); \
47 _SEH2_TRY { \
48 ret = g_free((HeapHandle), (Flags), (Count), (Array)); \
49 err = GetLastError(); \
50 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
51 threw = _SEH2_GetExceptionCode(); \
52 } \
53 _SEH2_END; \
54 ok((ret) == (ret_expected), "ret excepted %d, but %d\n", (ret_expected), (ret)); \
55 ok((err) == (err_expected), "err excepted %d, but %d\n", (err_expected), (err)); \
56 ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", (threw_excepted), (threw));
57
58 #define ASSUME_ARRAY_ITEMS_ARE_NULL() \
59 ok(Array[0] == NULL, "Array[0] is expected as NULL\n"); \
60 ok(Array[1] == NULL, "Array[1] is expected as NULL\n"); \
61 ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
62
63 #define INT_EXPECTED(var,value) \
64 ok((var) == (value), #var " expected %d, but %d\n", (value), (var))
65
66 static void
set_array(PVOID * array,PVOID p0,PVOID p1,PVOID p2)67 set_array(PVOID *array, PVOID p0, PVOID p1, PVOID p2)
68 {
69 array[0] = p0;
70 array[1] = p1;
71 array[2] = p2;
72 }
73
74 static void
MultiHeapAllocTest()75 MultiHeapAllocTest()
76 {
77 INT ret, threw, err;
78 HANDLE HeapHandle = GetProcessHeap();
79 PVOID Array[3] = {NULL, NULL, NULL};
80
81 // HeapHandle is non-NULL and array is NULL
82 TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, NULL);
83 TEST_ALLOC(0, -1, 0xC0000005, HeapHandle, 0, 0, 1, NULL);
84 TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, NULL);
85 TEST_ALLOC(0, -1, 0xC0000005, HeapHandle, 0, 1, 1, NULL);
86
87 // Array is non-NULL and contents are NULL
88 set_array(Array, NULL, NULL, NULL);
89 TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, Array);
90 ASSUME_ARRAY_ITEMS_ARE_NULL();
91
92 set_array(Array, NULL, NULL, NULL);
93 TEST_ALLOC(1, -1, 0, HeapHandle, 0, 0, 1, Array);
94 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
95 ok(Array[1] == NULL, "Array[1] is expected as NULL\n");
96 ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
97
98 set_array(Array, NULL, NULL, NULL);
99 TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, Array);
100 ASSUME_ARRAY_ITEMS_ARE_NULL();
101
102 set_array(Array, NULL, NULL, NULL);
103 TEST_ALLOC(1, -1, 0, HeapHandle, 0, 1, 1, Array);
104 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
105 ok(Array[1] == NULL, "Array[1] is expected as NULL\n");
106 ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
107
108 set_array(Array, NULL, NULL, NULL);
109 TEST_ALLOC(2, -1, 0, HeapHandle, 0, 1, 2, Array);
110 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
111 ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
112 ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
113
114 set_array(Array, NULL, NULL, NULL);
115 TEST_ALLOC(3, -1, 0, HeapHandle, 0, 1, 3, Array);
116 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
117 ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
118 ok(Array[2] != NULL, "Array[2] is expected as non-NULL\n");
119
120 // Array is non-NULL and contents are invalid pointers
121 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
122 TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, Array);
123 ok(Array[0] == (PVOID)1, "Array[0] is expected as 1\n");
124 ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n");
125 ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
126
127 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
128 TEST_ALLOC(1, -1, 0, HeapHandle, 0, 0, 1, Array);
129 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
130 ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n");
131 ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
132
133 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
134 TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, Array);
135 ok(Array[0] == (PVOID)1, "Array[0] is expected as 1\n");
136 ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n");
137 ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
138
139 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
140 TEST_ALLOC(1, -1, 0, HeapHandle, 0, 1, 1, Array);
141 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
142 ok(Array[1] == (PVOID)2, "Array[1] is expected as non-NULL\n");
143 ok(Array[2] == (PVOID)3, "Array[2] is expected as NULL\n");
144
145 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
146 TEST_ALLOC(2, -1, 0, HeapHandle, 0, 1, 2, Array);
147 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
148 ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
149 ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
150
151 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
152 TEST_ALLOC(3, -1, 0, HeapHandle, 0, 1, 3, Array);
153 ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
154 ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
155 ok(Array[2] != NULL, "Array[2] is expected as non-NULL\n");
156
157 // Array is non-NULL and too large to allocate
158 set_array(Array, NULL, NULL, NULL);
159 TEST_ALLOC_NO_RET(ERROR_NOT_ENOUGH_MEMORY, 0, HeapHandle, 0, 0x5FFFFFFF, 3, Array);
160 ok(ret != 3, "excepted not allocated");
161 set_array(Array, NULL, NULL, NULL);
162 TEST_ALLOC_NO_RET(ERROR_NOT_ENOUGH_MEMORY, 0xC0000017, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 0x5FFFFFFF, 3, Array);
163 ok(ret != 3, "excepted not allocated");
164 }
165
166 static void
MultiHeapFreeTest()167 MultiHeapFreeTest()
168 {
169 INT ret, threw, err;
170 HANDLE HeapHandle = GetProcessHeap();
171 PVOID Array[3] = {NULL, NULL, NULL};
172
173 // HeapHandle is non-NULL and array is NULL
174 TEST_FREE(0, -1, 0, HeapHandle, 0, 0, NULL);
175 TEST_FREE(0, -1, 0, HeapHandle, 0, 0, NULL);
176 TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 1, NULL);
177 TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 2, NULL);
178 TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 3, NULL);
179
180 // Array is non-NULL and contents are NULL
181 set_array(Array, NULL, NULL, NULL);
182 TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
183 set_array(Array, NULL, NULL, NULL);
184 TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array);
185 set_array(Array, NULL, NULL, NULL);
186 TEST_FREE(2, -1, 0, HeapHandle, 0, 2, Array);
187 set_array(Array, NULL, NULL, NULL);
188 TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array);
189
190 // Array is non-NULL and contents are invalid pointers
191 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
192 TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
193 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
194 TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 1, Array);
195 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
196 TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 2, Array);
197 set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
198 TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 3, Array);
199
200 // Array is non-NULL and contents are 1 valid pointer and 2 NULLs
201 set_array(Array, NULL, NULL, NULL);
202 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
203 INT_EXPECTED(ret, 1);
204 TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
205
206 set_array(Array, NULL, NULL, NULL);
207 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
208 INT_EXPECTED(ret, 1);
209 TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array);
210
211 set_array(Array, NULL, NULL, NULL);
212 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
213 INT_EXPECTED(ret, 1);
214 TEST_FREE(2, -1, 0, HeapHandle, 0, 2, Array);
215
216 set_array(Array, NULL, NULL, NULL);
217 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
218 INT_EXPECTED(ret, 1);
219 TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array);
220
221 // Array is non-NULL and contents are 1 valid pointer and 2 invalids
222 set_array(Array, NULL, (PVOID)2, (PVOID)3);
223 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
224 INT_EXPECTED(ret, 1);
225 TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
226
227 set_array(Array, NULL, (PVOID)2, (PVOID)3);
228 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
229 INT_EXPECTED(ret, 1);
230 TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array);
231
232 set_array(Array, NULL, (PVOID)2, (PVOID)3);
233 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
234 INT_EXPECTED(ret, 1);
235 TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 2, Array);
236
237 set_array(Array, NULL, (PVOID)2, (PVOID)3);
238 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
239 INT_EXPECTED(ret, 1);
240 TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 3, Array);
241
242 // Array is non-NULL and contents are 1 valid pointer and 2 invalids (generate exceptions)
243 set_array(Array, NULL, (PVOID)2, (PVOID)3);
244 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
245 INT_EXPECTED(ret, 1);
246 TEST_FREE(0, -1, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 0, Array);
247
248 set_array(Array, NULL, (PVOID)2, (PVOID)3);
249 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
250 INT_EXPECTED(ret, 1);
251 TEST_FREE(1, -1, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 1, Array);
252
253 set_array(Array, NULL, (PVOID)2, (PVOID)3);
254 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
255 INT_EXPECTED(ret, 1);
256 TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 2, Array);
257
258 set_array(Array, NULL, (PVOID)2, (PVOID)3);
259 ret = g_alloc(HeapHandle, 0, 1, 1, Array);
260 INT_EXPECTED(ret, 1);
261 TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 3, Array);
262
263 // Array is non-NULL and contents are 3 valid pointers
264 set_array(Array, NULL, NULL, NULL);
265 ret = g_alloc(HeapHandle, 0, 3, 3, Array);
266 INT_EXPECTED(ret, 3);
267 TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array);
268 }
269
START_TEST(RtlMultipleAllocateHeap)270 START_TEST(RtlMultipleAllocateHeap)
271 {
272 HINSTANCE ntdll = LoadLibraryA("ntdll");
273
274 g_alloc = (FN_RtlMultipleAllocateHeap)GetProcAddress(ntdll, "RtlMultipleAllocateHeap");
275 g_free = (FN_RtlMultipleFreeHeap)GetProcAddress(ntdll, "RtlMultipleFreeHeap");
276
277 if (!g_alloc || !g_free)
278 {
279 skip("RtlMultipleAllocateHeap or RtlMultipleFreeHeap not found\n");
280 }
281 else
282 {
283 MultiHeapAllocTest();
284 MultiHeapFreeTest();
285 }
286
287 FreeLibrary(ntdll);
288 }
289