[sanitizer] Change the way GetThreadStackAndTls() obtains the thread descriptor address.

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.

llvm-svn: 182853
This commit is contained in:
Sergey Matveev 2013-05-29 13:07:42 +00:00
parent 677003140c
commit 89bcec8117
3 changed files with 45 additions and 26 deletions

View File

@ -55,6 +55,8 @@ void AdjustStackSizeLinux(void *attr, int verbosity);
// Exposed for testing.
uptr ThreadDescriptorSize();
uptr ThreadSelf();
uptr ThreadSelfOffset();
// Matches a library's file name against a base name (stripping path and version
// information).

View File

@ -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 @@ uptr GetTlsSize() {
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;

View File

@ -19,9 +19,6 @@
#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>
@ -29,10 +26,6 @@
#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 @@ 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);
#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_TRUE((bool)thread_self_offset_test_func(0));
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());
}