[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