forked from mirrors/gecko-dev
Bug 1803322 - Use non-inlinable thread-local helpers in TestNativeNt and TestSafeThreadLocal. r=glandium
Differential Revision: https://phabricator.services.mozilla.com/D163487
This commit is contained in:
parent
8b95e44d5b
commit
40af2563e6
2 changed files with 22 additions and 10 deletions
|
|
@ -25,10 +25,16 @@ MOZ_NEVER_INLINE PVOID SwapThreadLocalStoragePointer(PVOID aNewValue) {
|
||||||
|
|
||||||
static mozilla::freestanding::SafeThreadLocal<int*> gTheStorage;
|
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) {
|
static unsigned int __stdcall TestNonMainThread(void* aArg) {
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
gTheStorage.set(&i);
|
setTheStorage(&i);
|
||||||
if (gTheStorage.get() != &i) {
|
if (getTheStorage() != &i) {
|
||||||
printf(
|
printf(
|
||||||
"TEST-FAILED | TestSafeThreadLocal | "
|
"TEST-FAILED | TestSafeThreadLocal | "
|
||||||
"A value is not correctly stored in the thread-local storage.\n");
|
"A value is not correctly stored in the thread-local storage.\n");
|
||||||
|
|
@ -43,7 +49,7 @@ extern "C" int wmain(int argc, wchar_t* argv[]) {
|
||||||
|
|
||||||
auto origHead = SwapThreadLocalStoragePointer(nullptr);
|
auto origHead = SwapThreadLocalStoragePointer(nullptr);
|
||||||
// Setting gTheStorage when TLS is null.
|
// Setting gTheStorage when TLS is null.
|
||||||
gTheStorage.set(&dummy);
|
setTheStorage(&dummy);
|
||||||
SwapThreadLocalStoragePointer(origHead);
|
SwapThreadLocalStoragePointer(origHead);
|
||||||
|
|
||||||
nsAutoHandle handles[8];
|
nsAutoHandle handles[8];
|
||||||
|
|
@ -53,7 +59,7 @@ extern "C" int wmain(int argc, wchar_t* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
if (gTheStorage.get() != &dummy) {
|
if (getTheStorage() != &dummy) {
|
||||||
printf(
|
printf(
|
||||||
"TEST-FAILED | TestSafeThreadLocal | "
|
"TEST-FAILED | TestSafeThreadLocal | "
|
||||||
"A value is not correctly stored in the global scope.\n");
|
"A value is not correctly stored in the global scope.\n");
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,12 @@ const wchar_t kPrefixedHex16[] = L"Pabcdef0123456789.dll";
|
||||||
const uint32_t kTlsDataValue = 1234;
|
const uint32_t kTlsDataValue = 1234;
|
||||||
static MOZ_THREAD_LOCAL(uint32_t) sTlsData;
|
static MOZ_THREAD_LOCAL(uint32_t) sTlsData;
|
||||||
|
|
||||||
|
// 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 uint32_t getTlsData() { return sTlsData.get(); }
|
||||||
|
MOZ_NEVER_INLINE void setTlsData(uint32_t x) { sTlsData.set(x); }
|
||||||
|
|
||||||
const char kFailFmt[] =
|
const char kFailFmt[] =
|
||||||
"TEST-FAILED | NativeNt | %s(%s) should have returned %s but did not\n";
|
"TEST-FAILED | NativeNt | %s(%s) should have returned %s but did not\n";
|
||||||
|
|
||||||
|
|
@ -419,13 +425,13 @@ int wmain(int argc, wchar_t* argv[]) {
|
||||||
bool isExceptionThrown = false;
|
bool isExceptionThrown = false;
|
||||||
// Touch sTlsData.get() several times to prevent the call to sTlsData.set()
|
// Touch sTlsData.get() several times to prevent the call to sTlsData.set()
|
||||||
// from being optimized out in PGO build.
|
// from being optimized out in PGO build.
|
||||||
printf("sTlsData#1 = %08x\n", sTlsData.get());
|
printf("sTlsData#1 = %08x\n", getTlsData());
|
||||||
MOZ_SEH_TRY {
|
MOZ_SEH_TRY {
|
||||||
// Need to call SwapThreadLocalStoragePointer inside __try to make sure
|
// Need to call SwapThreadLocalStoragePointer inside __try to make sure
|
||||||
// accessing sTlsData is caught by SEH. This is due to clang's design.
|
// accessing sTlsData is caught by SEH. This is due to clang's design.
|
||||||
// https://bugs.llvm.org/show_bug.cgi?id=44174.
|
// https://bugs.llvm.org/show_bug.cgi?id=44174.
|
||||||
origTlsHead = SwapThreadLocalStoragePointer(nullptr);
|
origTlsHead = SwapThreadLocalStoragePointer(nullptr);
|
||||||
sTlsData.set(~kTlsDataValue);
|
setTlsData(~kTlsDataValue);
|
||||||
}
|
}
|
||||||
MOZ_SEH_EXCEPT(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
|
MOZ_SEH_EXCEPT(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
|
||||||
? EXCEPTION_EXECUTE_HANDLER
|
? EXCEPTION_EXECUTE_HANDLER
|
||||||
|
|
@ -433,10 +439,10 @@ int wmain(int argc, wchar_t* argv[]) {
|
||||||
isExceptionThrown = true;
|
isExceptionThrown = true;
|
||||||
}
|
}
|
||||||
SwapThreadLocalStoragePointer(origTlsHead);
|
SwapThreadLocalStoragePointer(origTlsHead);
|
||||||
printf("sTlsData#2 = %08x\n", sTlsData.get());
|
printf("sTlsData#2 = %08x\n", getTlsData());
|
||||||
sTlsData.set(kTlsDataValue);
|
setTlsData(kTlsDataValue);
|
||||||
printf("sTlsData#3 = %08x\n", sTlsData.get());
|
printf("sTlsData#3 = %08x\n", getTlsData());
|
||||||
if (!isExceptionThrown || sTlsData.get() != kTlsDataValue) {
|
if (!isExceptionThrown || getTlsData() != kTlsDataValue) {
|
||||||
printf(
|
printf(
|
||||||
"TEST-FAILED | NativeNt | RtlGetThreadLocalStoragePointer() is "
|
"TEST-FAILED | NativeNt | RtlGetThreadLocalStoragePointer() is "
|
||||||
"broken\n");
|
"broken\n");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue