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