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