3d40df76086257d7a7216257cbc96bb66dbed191
[reactos.git] / modules / rostests / apitests / kernel32 / FLS.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Tests for FLS implementation details
5 * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8 #include "precomp.h"
9 #include <ndk/pstypes.h>
10 #include <ndk/rtlfuncs.h>
11
12 /* XP does not have these functions */
13 static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
14 static BOOL (WINAPI *pFlsFree)(DWORD);
15 static PVOID (WINAPI *pFlsGetValue)(DWORD);
16 static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID);
17
18
19 #define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock)
20 #define WINVER_2003 0x0502
21
22 static DWORD g_WinVersion = 0;
23 PVOID g_FlsData1 = NULL;
24 LONG g_FlsCalled1 = 0;
25 PVOID g_FlsData2 = NULL;
26 LONG g_FlsCalled2 = 0;
27 PVOID g_FlsData3 = NULL;
28 LONG g_FlsCalled3 = 0;
29 BOOL g_FlsExcept3 = FALSE;
30
31
32 VOID WINAPI FlsCallback1(PVOID lpFlsData)
33 {
34 ok(lpFlsData == g_FlsData1, "Expected g_FlsData1(%p), got %p\n", g_FlsData1, lpFlsData);
35 InterlockedIncrement(&g_FlsCalled1);
36 }
37
38 VOID WINAPI FlsCallback2(PVOID lpFlsData)
39 {
40 ok(lpFlsData == g_FlsData2, "Expected g_FlsData2(%p), got %p\n", g_FlsData2, lpFlsData);
41 InterlockedIncrement(&g_FlsCalled2);
42 }
43
44 VOID WINAPI FlsCallback3(PVOID lpFlsData)
45 {
46 ok(lpFlsData == g_FlsData3, "Expected g_FlsData3(%p), got %p\n", g_FlsData3, lpFlsData);
47
48 if (g_WinVersion <= WINVER_2003)
49 ok(RtlIsCriticalSectionLockedByThread(NtCurrentPeb()->FastPebLock), "Expected lock on PEB\n");
50 InterlockedIncrement(&g_FlsCalled3);
51 if (g_FlsExcept3)
52 {
53 RaiseException(ERROR_INVALID_PARAMETER, EXCEPTION_NONCONTINUABLE, 0, NULL);
54 }
55 }
56
57 typedef struct _FLS_CALLBACK_INFO
58 {
59 PFLS_CALLBACK_FUNCTION lpCallback;
60 PVOID Unknown;
61 } FLS_CALLBACK_INFO, *PFLS_CALLBACK_INFO;
62
63
64 void ok_fls_(DWORD dwIndex, PVOID pValue, PFLS_CALLBACK_FUNCTION lpCallback)
65 {
66 PFLS_CALLBACK_INFO FlsCallback;
67 PVOID* FlsData;
68 PVOID gotValue;
69
70 FlsCallback = (PFLS_CALLBACK_INFO)NtCurrentPeb()->FlsCallback;
71 FlsData = (PVOID*)NtCurrentTeb()->FlsData;
72
73 winetest_ok(FlsData != NULL, "Expected FlsData\n");
74 winetest_ok(FlsCallback != NULL, "Expected FlsCallback\n");
75
76 if (FlsData == NULL || FlsCallback == NULL)
77 {
78 winetest_skip("Unable to continue test\n");
79 return;
80 }
81
82 if (g_WinVersion <= WINVER_2003)
83 {
84 winetest_ok(NtCurrentPeb()->FlsCallback[dwIndex] == lpCallback,
85 "Expected NtCurrentPeb()->FlsCallback[%lu] to be %p, was %p\n",
86 dwIndex,
87 lpCallback,
88 NtCurrentPeb()->FlsCallback[dwIndex]);
89 }
90 else
91 {
92 winetest_ok(FlsCallback[dwIndex].lpCallback == lpCallback,
93 "Expected FlsCallback[%lu].lpCallback to be %p, was %p\n",
94 dwIndex,
95 lpCallback,
96 FlsCallback[dwIndex].lpCallback);
97 if (lpCallback != &FlsCallback3 || !g_FlsExcept3)
98 {
99 winetest_ok(FlsCallback[dwIndex].Unknown == NULL,
100 "Expected FlsCallback[%lu].Unknown to be %p, was %p\n",
101 dwIndex,
102 NULL,
103 FlsCallback[dwIndex].Unknown);
104 }
105 }
106 winetest_ok(FlsData[dwIndex + 2] == pValue,
107 "Expected FlsData[%lu + 2] to be %p, was %p\n",
108 dwIndex,
109 pValue,
110 FlsData[dwIndex + 2]);
111
112 gotValue = pFlsGetValue(dwIndex);
113 winetest_ok(gotValue == pValue, "Expected FlsGetValue(%lu) to be %p, was %p\n", dwIndex, pValue, gotValue);
114 }
115
116 #define ok_fls (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : ok_fls_
117
118 static VOID init_funcs(void)
119 {
120 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
121
122 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f);
123 X(FlsAlloc);
124 X(FlsFree);
125 X(FlsGetValue);
126 X(FlsSetValue);
127 #undef X
128 }
129
130
131
132 START_TEST(FLS)
133 {
134 RTL_OSVERSIONINFOW rtlinfo = { sizeof(rtlinfo) };
135 DWORD dwIndex1, dwIndex2, dwIndex3, dwErr;
136 BOOL bRet;
137
138 init_funcs();
139 if (!pFlsAlloc || !pFlsFree || !pFlsGetValue || !pFlsSetValue)
140 {
141 skip("Fls functions not available\n");
142 return;
143 }
144
145 RtlGetVersion(&rtlinfo);
146 g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion;
147
148 dwIndex1 = pFlsAlloc(FlsCallback1);
149 ok(dwIndex1 != FLS_OUT_OF_INDEXES, "Unable to allocate FLS index\n");
150 dwIndex2 = pFlsAlloc(FlsCallback2);
151 ok(dwIndex2 != FLS_OUT_OF_INDEXES, "Unable to allocate FLS index\n");
152 ok(dwIndex1 != dwIndex2, "Expected different indexes, got %lu\n", dwIndex1);
153
154 dwIndex3 = pFlsAlloc(FlsCallback3);
155 ok(dwIndex3 != FLS_OUT_OF_INDEXES, "Unable to allocate FLS index\n");
156 ok(dwIndex1 != dwIndex3, "Expected different indexes, got %lu\n", dwIndex1);
157
158 if (dwIndex1 == FLS_OUT_OF_INDEXES || dwIndex2 == FLS_OUT_OF_INDEXES || dwIndex3 == FLS_OUT_OF_INDEXES)
159 {
160 skip("Unable to continue test\n");
161 return;
162 }
163
164 ok_fls(dwIndex1, g_FlsData1, &FlsCallback1);
165 ok_fls(dwIndex2, g_FlsData2, &FlsCallback2);
166 ok_fls(dwIndex3, g_FlsData3, &FlsCallback3);
167
168 g_FlsData1 = (PVOID)0x123456;
169 ok(pFlsSetValue(dwIndex1, g_FlsData1), "FlsSetValue(%lu, %p) failed\n", dwIndex1, g_FlsData1);
170
171 ok_fls(dwIndex1, g_FlsData1, &FlsCallback1);
172 ok_fls(dwIndex2, g_FlsData2, &FlsCallback2);
173 ok_fls(dwIndex3, g_FlsData3, &FlsCallback3);
174
175 ok_int(g_FlsCalled1, 0);
176 ok_int(g_FlsCalled2, 0);
177 ok_int(g_FlsCalled3, 0);
178
179 g_FlsData2 = (PVOID)0x9876112;
180 ok(pFlsSetValue(dwIndex2, g_FlsData2), "FlsSetValue(%lu, %p) failed\n", dwIndex2, g_FlsData2);
181
182 ok_fls(dwIndex1, g_FlsData1, &FlsCallback1);
183 ok_fls(dwIndex2, g_FlsData2, &FlsCallback2);
184 ok_fls(dwIndex3, g_FlsData3, &FlsCallback3);
185
186
187 ok_int(g_FlsCalled1, 0);
188 ok_int(g_FlsCalled2, 0);
189 ok_int(g_FlsCalled3, 0);
190
191 g_FlsData3 = (PVOID)0x98762;
192 ok(pFlsSetValue(dwIndex3, g_FlsData3), "FlsSetValue(%lu, %p) failed\n", dwIndex3, g_FlsData3);
193
194 ok_fls(dwIndex1, g_FlsData1, &FlsCallback1);
195 ok_fls(dwIndex2, g_FlsData2, &FlsCallback2);
196 ok_fls(dwIndex3, g_FlsData3, &FlsCallback3);
197
198 ok_int(g_FlsCalled1, 0);
199 ok_int(g_FlsCalled2, 0);
200 ok_int(g_FlsCalled3, 0);
201
202 ok(pFlsFree(dwIndex1) == TRUE, "FlsFree(%lu) failed\n", dwIndex1);
203 g_FlsData1 = NULL;
204
205 ok_fls(dwIndex1, g_FlsData1, NULL);
206 ok_fls(dwIndex2, g_FlsData2, &FlsCallback2);
207 ok_fls(dwIndex3, g_FlsData3, &FlsCallback3);
208
209 ok_int(g_FlsCalled1, 1);
210 ok_int(g_FlsCalled2, 0);
211 ok_int(g_FlsCalled3, 0);
212
213 g_FlsExcept3 = TRUE;
214 _SEH2_TRY
215 {
216 bRet = pFlsFree(dwIndex3);
217 dwErr = GetLastError();
218 }
219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
220 {
221 bRet = 12345;
222 dwErr = 0xdeaddead;
223 }
224 _SEH2_END;
225 ok(RtlIsCriticalSectionLockedByThread(NtCurrentPeb()->FastPebLock) == FALSE, "Expected no lock on PEB\n");
226
227 ok(bRet == 12345, "FlsFree(%lu) should have failed, got %u\n", dwIndex3, bRet);
228 ok(dwErr == 0xdeaddead, "Expected GetLastError() to be 0xdeaddead, was %lx\n", dwErr);
229
230 ok_fls(dwIndex1, g_FlsData1, NULL);
231 ok_fls(dwIndex2, g_FlsData2, &FlsCallback2);
232 ok_fls(dwIndex3, g_FlsData3, &FlsCallback3);
233
234 ok_int(g_FlsCalled1, 1);
235 ok_int(g_FlsCalled2, 0);
236 ok_int(g_FlsCalled3, 1);
237 }