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