TestSafeThreadLocal.cpp (2672B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #define MOZ_USE_LAUNCHER_ERROR 8 9 #include "freestanding/SafeThreadLocal.h" 10 11 #include "mozilla/NativeNt.h" 12 #include "nsWindowsHelpers.h" 13 14 #include <process.h> 15 #include <stdio.h> 16 17 // Need a non-inline function to bypass compiler optimization that the thread 18 // local storage pointer is cached in a register before accessing a thread-local 19 // variable. 20 MOZ_NEVER_INLINE PVOID SwapThreadLocalStoragePointer(PVOID aNewValue) { 21 auto oldValue = mozilla::nt::RtlGetThreadLocalStoragePointer(); 22 mozilla::nt::RtlSetThreadLocalStoragePointerForTestingOnly(aNewValue); 23 return oldValue; 24 } 25 26 static mozilla::freestanding::SafeThreadLocal<int*> gTheStorage; 27 28 // Need non-inline functions to bypass compiler optimization that the thread 29 // local storage pointer is cached in a register before accessing a thread-local 30 // variable. See bug 1803322 for a motivating example. 31 MOZ_NEVER_INLINE int* getTheStorage() { return gTheStorage.get(); } 32 MOZ_NEVER_INLINE void setTheStorage(int* p) { gTheStorage.set(p); } 33 34 static unsigned int __stdcall TestNonMainThread(void* aArg) { 35 for (int i = 0; i < 100; ++i) { 36 setTheStorage(&i); 37 if (getTheStorage() != &i) { 38 printf( 39 "TEST-FAILED | TestSafeThreadLocal | " 40 "A value is not correctly stored in the thread-local storage.\n"); 41 return 1; 42 } 43 } 44 return 0; 45 } 46 47 extern "C" int wmain(int argc, wchar_t* argv[]) { 48 int dummy = 0x1234; 49 50 auto origHead = SwapThreadLocalStoragePointer(nullptr); 51 // Setting gTheStorage when TLS is null. 52 setTheStorage(&dummy); 53 SwapThreadLocalStoragePointer(origHead); 54 55 nsAutoHandle handles[8]; 56 for (auto& handle : handles) { 57 handle.own(reinterpret_cast<HANDLE>( 58 ::_beginthreadex(nullptr, 0, TestNonMainThread, nullptr, 0, nullptr))); 59 } 60 61 for (int i = 0; i < 100; ++i) { 62 if (getTheStorage() != &dummy) { 63 printf( 64 "TEST-FAILED | TestSafeThreadLocal | " 65 "A value is not correctly stored in the global scope.\n"); 66 return 1; 67 } 68 } 69 70 for (auto& handle : handles) { 71 ::WaitForSingleObject(handle, INFINITE); 72 73 #if !defined(MOZ_ASAN) 74 // ASAN builds under Windows 11 can have unexpected thread exit codes. 75 // See bug 1798796 76 DWORD exitCode; 77 if (!::GetExitCodeThread(handle, &exitCode) || exitCode) { 78 return 1; 79 } 80 #endif // !defined(MOZ_ASAN) 81 } 82 83 return 0; 84 }