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 }
238