diff options
author | Sergey Matveev <earthdok@google.com> | 2013-05-07 14:41:43 +0000 |
---|---|---|
committer | Sergey Matveev <earthdok@google.com> | 2013-05-07 14:41:43 +0000 |
commit | 24323de08fa8850712d56621bff29dbbbd0285a9 (patch) | |
tree | 2ac35bf2be079d42730993b97616e163d5ab4b84 /lib | |
parent | 2be3a283939d4fc14ad86f6cd8be34b1468f22ba (diff) | |
download | compiler-rt-24323de08fa8850712d56621bff29dbbbd0285a9.tar.gz |
[sanitizer] Move GetThreadStackAndTls from TSan to sanitizer_common.
Move this function to sanitizer_common because LSan uses it too. Also, fix a bug
where the TLS range reported for main thread was off by the size of the thread
descriptor from libc (TSan doesn't care much, but for LSan it's critical).
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@181322 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.cc | 47 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.h | 3 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_mac.cc | 10 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 10 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_common_test.cc | 45 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_linux_test.cc | 29 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_platform.h | 2 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_platform_linux.cc | 31 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_platform_mac.cc | 8 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_platform_windows.cc | 8 | ||||
-rw-r--r-- | lib/tsan/tests/unit/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/tsan/tests/unit/tsan_platform_test.cc | 64 |
13 files changed, 146 insertions, 114 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9df510b85..7c18f1794 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -45,6 +45,8 @@ uptr GetTid(); uptr GetThreadSelf(); void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom); +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size); // Memory management void *MmapOrDie(uptr size, const char *mem_type); diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 194c6a80e..c8adb8e8d 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -24,6 +24,7 @@ #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include <asm/prctl.h> #include <dlfcn.h> #include <errno.h> #include <fcntl.h> @@ -63,6 +64,8 @@ const int FUTEX_WAKE = 1; # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 #endif +extern "C" int arch_prctl(int code, __sanitizer::uptr *addr); + namespace __sanitizer { // --------------- sanitizer_libc.h @@ -761,6 +764,50 @@ uptr GetTlsSize() { return g_tls_size; } +// sizeof(struct thread) from glibc. +#ifdef __x86_64__ +const uptr kThreadDescriptorSize = 2304; + +uptr ThreadDescriptorSize() { + return kThreadDescriptorSize; +} +#endif + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#ifndef SANITIZER_GO +#ifdef __x86_64__ + arch_prctl(ARCH_GET_FS, tls_addr); + *tls_size = GetTlsSize(); + *tls_addr -= *tls_size; + *tls_addr += kThreadDescriptorSize; +#else + *tls_addr = 0; + *tls_size = 0; +#endif + + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + + if (!main) { + // If stack and tls intersect, make them non-intersecting. + if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { + CHECK_GT(*tls_addr + *tls_size, *stk_addr); + CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); + *stk_size -= *tls_size; + *tls_addr = *stk_addr + *stk_size; + } + } +#else // SANITIZER_GO + *stk_addr = 0; + *stk_size = 0; + *tls_addr = 0; + *tls_size = 0; +#endif // SANITIZER_GO +} + void AdjustStackSizeLinux(void *attr_, int verbosity) { pthread_attr_t *attr = (pthread_attr_t *)attr_; uptr stackaddr = 0; diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index 13b60fa91..2545e631f 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -52,6 +52,9 @@ class ThreadLister { void AdjustStackSizeLinux(void *attr, int verbosity); +// Exposed for testing. +uptr ThreadDescriptorSize(); + } // namespace __sanitizer #endif // SANITIZER_LINUX_H diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index baac4a932..08d48bca3 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -339,6 +339,16 @@ uptr GetTlsSize() { void InitTlsSize() { } +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = 0; + *tls_size = 0; +} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 88023e676..48874a1dc 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -336,6 +336,16 @@ uptr GetTlsSize() { void InitTlsSize() { } +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = 0; + *tls_size = 0; +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 0a777bd35..be752a596 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -112,4 +112,49 @@ TEST(SanitizerCommon, InternalVector) { } } +void TestThreadInfo(bool main) { + uptr stk_addr = 0; + uptr stk_size = 0; + uptr tls_addr = 0; + uptr tls_size = 0; + GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size); + + int stack_var; + EXPECT_NE(stk_addr, (uptr)0); + EXPECT_NE(stk_size, (uptr)0); + EXPECT_GT((uptr)&stack_var, stk_addr); + EXPECT_LT((uptr)&stack_var, stk_addr + stk_size); + +#if defined(__linux__) && defined(__x86_64__) + static __thread int thread_var; + EXPECT_NE(tls_addr, (uptr)0); + EXPECT_NE(tls_size, (uptr)0); + EXPECT_GT((uptr)&thread_var, tls_addr); + EXPECT_LT((uptr)&thread_var, tls_addr + tls_size); + + // Ensure that tls and stack do not intersect. + uptr tls_end = tls_addr + tls_size; + EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size); + EXPECT_TRUE(tls_end < stk_addr || tls_end >= stk_addr + stk_size); + EXPECT_TRUE((tls_addr < stk_addr) == (tls_end < stk_addr)); +#endif +} + +static void *WorkerThread(void *arg) { + TestThreadInfo(false); + return 0; +} + +TEST(SanitizerCommon, ThreadStackTlsMain) { + InitTlsSize(); + TestThreadInfo(true); +} + +TEST(Platform, ThreadStackTlsWorker) { + InitTlsSize(); + pthread_t t; + pthread_create(&t, 0, WorkerThread, 0); + pthread_join(t, 0); +} + } // namespace __sanitizer diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index 0560fb57b..9a3f9270d 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -18,6 +18,9 @@ #include "sanitizer_common/sanitizer_common.h" +#ifdef __x86_64__ +#include <asm/prctl.h> +#endif #include <pthread.h> #include <sched.h> #include <stdlib.h> @@ -25,6 +28,10 @@ #include <algorithm> #include <vector> +#ifdef __x86_64__ +extern "C" int arch_prctl(int code, __sanitizer::uptr *addr); +#endif + namespace __sanitizer { struct TidReporterArgument { @@ -194,6 +201,28 @@ TEST(SanitizerCommon, SetEnvTest) { EXPECT_EQ(0, getenv(kEnvName)); } +#ifdef __x86_64__ +// libpthread puts the thread descriptor (%fs:0x0) at the end of stack space. +void *thread_descriptor_test_func(void *arg) { + uptr fs; + arch_prctl(ARCH_GET_FS, &fs); + pthread_attr_t attr; + pthread_getattr_np(pthread_self(), &attr); + void *stackaddr; + uptr stacksize; + pthread_attr_getstack(&attr, &stackaddr, &stacksize); + return (void *)((uptr)stackaddr + stacksize - fs); +} + +TEST(SanitizerLinux, ThreadDescriptorSize) { + pthread_t tid; + void *result; + pthread_create(&tid, 0, thread_descriptor_test_func, 0); + ASSERT_EQ(0, pthread_join(tid, &result)); + EXPECT_EQ((uptr)result, ThreadDescriptorSize()); +} +#endif + } // namespace __sanitizer #endif // __linux__ diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h index b308a7112..666b4d0c4 100644 --- a/lib/tsan/rtl/tsan_platform.h +++ b/lib/tsan/rtl/tsan_platform.h @@ -154,8 +154,6 @@ void internal_start_thread(void(*func)(void*), void *arg); // Says whether the addr relates to a global var. // Guesses with high probability, may yield both false positives and negatives. bool IsGlobalVar(uptr addr); -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size); int ExtractResolvFDs(void *state, int *fds, int nfd); } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 00b862104..df07ac638 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -23,7 +23,6 @@ #include "tsan_rtl.h" #include "tsan_flags.h" -#include <asm/prctl.h> #include <fcntl.h> #include <pthread.h> #include <signal.h> @@ -46,7 +45,6 @@ #include <resolv.h> #include <malloc.h> -extern "C" int arch_prctl(int code, __sanitizer::uptr *addr); extern "C" struct mallinfo __libc_mallinfo(); namespace __tsan { @@ -358,35 +356,6 @@ const char *InitializePlatform() { return GetEnv(kTsanOptionsEnv); } -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { -#ifndef TSAN_GO - arch_prctl(ARCH_GET_FS, tls_addr); - *tls_size = GetTlsSize(); - *tls_addr -= *tls_size; - - uptr stack_top, stack_bottom; - GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); - *stk_addr = stack_bottom; - *stk_size = stack_top - stack_bottom; - - if (!main) { - // If stack and tls intersect, make them non-intersecting. - if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { - CHECK_GT(*tls_addr + *tls_size, *stk_addr); - CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); - *stk_size -= *tls_size; - *tls_addr = *stk_addr + *stk_size; - } - } -#else - *stk_addr = 0; - *stk_size = 0; - *tls_addr = 0; - *tls_size = 0; -#endif -} - bool IsGlobalVar(uptr addr) { return g_data_start && addr >= g_data_start && addr < g_data_end; } diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc index 5da985231..99d4533a4 100644 --- a/lib/tsan/rtl/tsan_platform_mac.cc +++ b/lib/tsan/rtl/tsan_platform_mac.cc @@ -90,14 +90,6 @@ void FinalizePlatform() { fflush(0); } -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { - *stk_addr = 0; - *stk_size = 0; - *tls_addr = 0; - *tls_size = 0; -} - } // namespace __tsan #endif // SANITIZER_MAC diff --git a/lib/tsan/rtl/tsan_platform_windows.cc b/lib/tsan/rtl/tsan_platform_windows.cc index 83d2f3930..711db72ce 100644 --- a/lib/tsan/rtl/tsan_platform_windows.cc +++ b/lib/tsan/rtl/tsan_platform_windows.cc @@ -42,14 +42,6 @@ void FinalizePlatform() { fflush(0); } -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { - *stk_addr = 0; - *stk_size = 0; - *tls_addr = 0; - *tls_size = 0; -} - } // namespace __tsan #endif // SANITIZER_WINDOWS diff --git a/lib/tsan/tests/unit/CMakeLists.txt b/lib/tsan/tests/unit/CMakeLists.txt index 52ebdb826..b25a56d8d 100644 --- a/lib/tsan/tests/unit/CMakeLists.txt +++ b/lib/tsan/tests/unit/CMakeLists.txt @@ -3,7 +3,6 @@ set(TSAN_UNIT_TESTS tsan_flags_test.cc tsan_mman_test.cc tsan_mutex_test.cc - tsan_platform_test.cc tsan_shadow_test.cc tsan_stack_test.cc tsan_suppressions_test.cc diff --git a/lib/tsan/tests/unit/tsan_platform_test.cc b/lib/tsan/tests/unit/tsan_platform_test.cc deleted file mode 100644 index 733cc54d3..000000000 --- a/lib/tsan/tests/unit/tsan_platform_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -//===-- tsan_platform_test.cc ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer (TSan), a race detector. -// -//===----------------------------------------------------------------------===// -#include "sanitizer_common/sanitizer_libc.h" -#include "tsan_platform.h" -#include "tsan_rtl.h" -#include "gtest/gtest.h" - -namespace __tsan { - -static void TestThreadInfo(bool main) { - ScopedInRtl in_rtl; - uptr stk_addr = 0; - uptr stk_size = 0; - uptr tls_addr = 0; - uptr tls_size = 0; - GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size); - // Printf("stk=%zx-%zx(%zu)\n", stk_addr, stk_addr + stk_size, stk_size); - // Printf("tls=%zx-%zx(%zu)\n", tls_addr, tls_addr + tls_size, tls_size); - - int stack_var; - EXPECT_NE(stk_addr, (uptr)0); - EXPECT_NE(stk_size, (uptr)0); - EXPECT_GT((uptr)&stack_var, stk_addr); - EXPECT_LT((uptr)&stack_var, stk_addr + stk_size); - - static __thread int thread_var; - EXPECT_NE(tls_addr, (uptr)0); - EXPECT_NE(tls_size, (uptr)0); - EXPECT_GT((uptr)&thread_var, tls_addr); - EXPECT_LT((uptr)&thread_var, tls_addr + tls_size); - - // Ensure that tls and stack do not intersect. - uptr tls_end = tls_addr + tls_size; - EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size); - EXPECT_TRUE(tls_end < stk_addr || tls_end >= stk_addr + stk_size); - EXPECT_TRUE((tls_addr < stk_addr) == (tls_end < stk_addr)); -} - -static void *WorkerThread(void *arg) { - TestThreadInfo(false); - return 0; -} - -TEST(Platform, ThreadInfoMain) { - TestThreadInfo(true); -} - -TEST(Platform, ThreadInfoWorker) { - pthread_t t; - pthread_create(&t, 0, WorkerThread, 0); - pthread_join(t, 0); -} - -} // namespace __tsan |