summaryrefslogtreecommitdiffstats
path: root/browser/app/winlauncher/test/TestSafeThreadLocal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'browser/app/winlauncher/test/TestSafeThreadLocal.cpp')
-rw-r--r--browser/app/winlauncher/test/TestSafeThreadLocal.cpp84
1 files changed, 84 insertions, 0 deletions
diff --git a/browser/app/winlauncher/test/TestSafeThreadLocal.cpp b/browser/app/winlauncher/test/TestSafeThreadLocal.cpp
new file mode 100644
index 0000000000..31af93c375
--- /dev/null
+++ b/browser/app/winlauncher/test/TestSafeThreadLocal.cpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#define MOZ_USE_LAUNCHER_ERROR
+
+#include "freestanding/SafeThreadLocal.h"
+
+#include "mozilla/NativeNt.h"
+#include "nsWindowsHelpers.h"
+
+#include <process.h>
+#include <stdio.h>
+
+// Need a non-inline function to bypass compiler optimization that the thread
+// local storage pointer is cached in a register before accessing a thread-local
+// variable.
+MOZ_NEVER_INLINE PVOID SwapThreadLocalStoragePointer(PVOID aNewValue) {
+ auto oldValue = mozilla::nt::RtlGetThreadLocalStoragePointer();
+ mozilla::nt::RtlSetThreadLocalStoragePointerForTestingOnly(aNewValue);
+ return oldValue;
+}
+
+static mozilla::freestanding::SafeThreadLocal<int*> gTheStorage;
+
+// Need non-inline functions to bypass compiler optimization that the thread
+// local storage pointer is cached in a register before accessing a thread-local
+// variable. See bug 1803322 for a motivating example.
+MOZ_NEVER_INLINE int* getTheStorage() { return gTheStorage.get(); }
+MOZ_NEVER_INLINE void setTheStorage(int* p) { gTheStorage.set(p); }
+
+static unsigned int __stdcall TestNonMainThread(void* aArg) {
+ for (int i = 0; i < 100; ++i) {
+ setTheStorage(&i);
+ if (getTheStorage() != &i) {
+ printf(
+ "TEST-FAILED | TestSafeThreadLocal | "
+ "A value is not correctly stored in the thread-local storage.\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+extern "C" int wmain(int argc, wchar_t* argv[]) {
+ int dummy = 0x1234;
+
+ auto origHead = SwapThreadLocalStoragePointer(nullptr);
+ // Setting gTheStorage when TLS is null.
+ setTheStorage(&dummy);
+ SwapThreadLocalStoragePointer(origHead);
+
+ nsAutoHandle handles[8];
+ for (auto& handle : handles) {
+ handle.own(reinterpret_cast<HANDLE>(
+ ::_beginthreadex(nullptr, 0, TestNonMainThread, nullptr, 0, nullptr)));
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ if (getTheStorage() != &dummy) {
+ printf(
+ "TEST-FAILED | TestSafeThreadLocal | "
+ "A value is not correctly stored in the global scope.\n");
+ return 1;
+ }
+ }
+
+ for (auto& handle : handles) {
+ ::WaitForSingleObject(handle, INFINITE);
+
+#if !defined(MOZ_ASAN)
+ // ASAN builds under Windows 11 can have unexpected thread exit codes.
+ // See bug 1798796
+ DWORD exitCode;
+ if (!::GetExitCodeThread(handle, &exitCode) || exitCode) {
+ return 1;
+ }
+#endif // !defined(MOZ_ASAN)
+ }
+
+ return 0;
+}