tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }