summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSergey Matveev <earthdok@google.com>2013-05-07 14:41:43 +0000
committerSergey Matveev <earthdok@google.com>2013-05-07 14:41:43 +0000
commit24323de08fa8850712d56621bff29dbbbd0285a9 (patch)
tree2ac35bf2be079d42730993b97616e163d5ab4b84 /lib
parent2be3a283939d4fc14ad86f6cd8be34b1468f22ba (diff)
downloadcompiler-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.h2
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc47
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h3
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc10
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc10
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc45
-rw-r--r--lib/sanitizer_common/tests/sanitizer_linux_test.cc29
-rw-r--r--lib/tsan/rtl/tsan_platform.h2
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc31
-rw-r--r--lib/tsan/rtl/tsan_platform_mac.cc8
-rw-r--r--lib/tsan/rtl/tsan_platform_windows.cc8
-rw-r--r--lib/tsan/tests/unit/CMakeLists.txt1
-rw-r--r--lib/tsan/tests/unit/tsan_platform_test.cc64
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