[PATCH] [sanitizer] Change the way GetThreadStackAndTls() obtains the thread descriptor address.
Sergey Matveev
earthdok at google.com
Tue May 28 06:53:21 PDT 2013
Hi dvyukov, kcc, glider,
Instead of using arch_prctl(ARCH_GET_FS), read the address from the
tread descriptor itself. This lets us avoid sandboxing issues. Also,
GetThreadStackAndTls() can now be implemented on i386.
http://llvm-reviews.chandlerc.com/D879
Files:
lib/sanitizer_common/sanitizer_linux.h
lib/sanitizer_common/sanitizer_linux_libcdep.cc
lib/sanitizer_common/tests/sanitizer_linux_test.cc
Index: lib/sanitizer_common/sanitizer_linux.h
===================================================================
--- lib/sanitizer_common/sanitizer_linux.h
+++ lib/sanitizer_common/sanitizer_linux.h
@@ -55,6 +55,8 @@
// Exposed for testing.
uptr ThreadDescriptorSize();
+uptr ThreadSelf();
+uptr ThreadSelfOffset();
// Matches a library's file name against a base name (stripping path and version
// information).
Index: lib/sanitizer_common/sanitizer_linux_libcdep.cc
===================================================================
--- lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -19,19 +19,12 @@
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
-#ifdef __x86_64__
-#include <asm/prctl.h>
-#endif
#include <dlfcn.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <unwind.h>
-#ifdef __x86_64__
-extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
-#endif
-
namespace __sanitizer {
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
@@ -200,20 +193,37 @@
return g_tls_size;
}
+#if defined(__x86_64__) || defined(i386)
// sizeof(struct thread) from glibc.
-#ifdef __x86_64__
-const uptr kThreadDescriptorSize = 2304;
+const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304);
uptr ThreadDescriptorSize() {
return kThreadDescriptorSize;
}
+
+// The offset at which pointer to self is located in the thread descriptor.
+const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
+
+uptr ThreadSelfOffset() {
+ return kThreadSelfOffset;
+}
+
+uptr ThreadSelf() {
+ uptr descr_addr;
+#ifdef __i386__
+ asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+#else
+ asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
#endif
+ return descr_addr;
+}
+#endif // defined(__x86_64__) || defined(i386)
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);
+#if defined(__x86_64__) || defined(i386)
+ *tls_addr = ThreadSelf();
*tls_size = GetTlsSize();
*tls_addr -= *tls_size;
*tls_addr += kThreadDescriptorSize;
Index: lib/sanitizer_common/tests/sanitizer_linux_test.cc
===================================================================
--- lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -19,20 +19,13 @@
#include "sanitizer_common/sanitizer_common.h"
#include "gtest/gtest.h"
-#ifdef __x86_64__
-#include <asm/prctl.h>
-#endif
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
-#ifdef __x86_64__
-extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
-#endif
-
namespace __sanitizer {
struct TidReporterArgument {
@@ -202,23 +195,37 @@
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);
+#if defined(__x86_64__) || defined(i386)
+void *thread_self_offset_test_func(void *arg) {
+ bool result =
+ *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
+ return (void *)result;
+}
+
+TEST(SanitizerLinux, ThreadSelfOffset) {
+ EXPECT_EQ(*(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()), ThreadSelf());
+ pthread_t tid;
+ void *result;
+ ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
+ ASSERT_EQ(0, pthread_join(tid, &result));
+ EXPECT_TRUE((bool)result);
+}
+
+// libpthread puts the thread descriptor at the end of stack space.
+void *thread_descriptor_size_test_func(void *arg) {
+ uptr descr_addr = ThreadSelf();
pthread_attr_t attr;
pthread_getattr_np(pthread_self(), &attr);
void *stackaddr;
- uptr stacksize;
+ size_t stacksize;
pthread_attr_getstack(&attr, &stackaddr, &stacksize);
- return (void *)((uptr)stackaddr + stacksize - fs);
+ return (void *)((uptr)stackaddr + stacksize - descr_addr);
}
TEST(SanitizerLinux, ThreadDescriptorSize) {
pthread_t tid;
void *result;
- pthread_create(&tid, 0, thread_descriptor_test_func, 0);
+ ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
ASSERT_EQ(0, pthread_join(tid, &result));
EXPECT_EQ((uptr)result, ThreadDescriptorSize());
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D879.1.patch
Type: text/x-patch
Size: 4503 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130528/79bdf47e/attachment.bin>
More information about the llvm-commits
mailing list