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