Commit da409929 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

base: Add Stack utilities

Adds:
- GetStackStart
- GetCurrentStackPosition
- GetStackSlot which translates a stack slot through ASAN
  if needed

Bug: v8:10354, chromium:1056170
Change-Id: I28e76f41de28415382f7cc32729e86d71e9f8f19
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2122033
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66890}
parent 0f4d68da
......@@ -96,5 +96,23 @@ void OS::SignalCodeMovingGC() {}
void OS::AdjustSchedulingParams() {}
// static
void* Stack::GetStackStart() {
pthread_attr_t attr;
int error;
pthread_attr_init(&attr);
error = pthread_attr_get_np(pthread_self(), &attr);
if (!error) {
void* base;
size_t size;
error = pthread_attr_getstack(&attr, &base, &size);
CHECK(!error);
pthread_attr_destroy(&attr);
return reinterpret_cast<uint8_t*>(base) + size;
}
pthread_attr_destroy(&attr);
return nullptr;
}
} // namespace base
} // namespace v8
......@@ -93,5 +93,10 @@ void OS::AdjustSchedulingParams() {
#endif
}
// static
void* Stack::GetStackStart() {
return pthread_get_stackaddr_np(pthread_self());
}
} // namespace base
} // namespace v8
......@@ -81,6 +81,10 @@ extern int madvise(caddr_t, size_t, int);
#define MADV_FREE MADV_DONTNEED
#endif
#if defined(V8_LIBC_GLIBC)
extern "C" void* __libc_stack_end; // NOLINT
#endif
namespace v8 {
namespace base {
......@@ -963,6 +967,40 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
USE(result);
}
// pthread_getattr_np used below is non portable (hence the _np suffix). We
// keep this version in POSIX as most Linux-compatible derivatives will
// support it. MacOS and FreeBSD are different here.
#if !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX)
// static
void* Stack::GetStackStart() {
pthread_attr_t attr;
int error = pthread_getattr_np(pthread_self(), &attr);
if (!error) {
void* base;
size_t size;
error = pthread_attr_getstack(&attr, &base, &size);
CHECK(!error);
pthread_attr_destroy(&attr);
return reinterpret_cast<uint8_t*>(base) + size;
}
pthread_attr_destroy(&attr);
#if defined(V8_LIBC_GLIBC)
// pthread_getattr_np can fail for the main thread. In this case
// just like NaCl we rely on the __libc_stack_end to give us
// the start of the stack.
// See https://code.google.com/p/nativeclient/issues/detail?id=3431.
return __libc_stack_end;
#endif // !defined(V8_LIBC_GLIBC)
return nullptr;
}
#endif // !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX)
// static
void* Stack::GetCurrentStackPosition() { return __builtin_frame_address(0); }
#undef LOG_TAG
#undef MAP_ANONYMOUS
#undef MADV_FREE
......
......@@ -1394,5 +1394,23 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
void OS::AdjustSchedulingParams() {}
// static
void* Stack::GetStackStart() {
#if defined(V8_TARGET_ARCH_32_BIT)
return reinterpret_cast<void*>(__readfsdword(offsetof(NT_TIB, StackBase)));
#else
return reinterpret_cast<void*>(__readgsqword(offsetof(NT_TIB64, StackBase)));
#endif
}
// static
void* Stack::GetCurrentStackPosition() {
#if V8_CC_MSVC
return _AddressOfReturnAddress();
#else
return __builtin_frame_address(0);
#endif
}
} // namespace base
} // namespace v8
......@@ -35,6 +35,10 @@
#include "src/base/qnx-math.h"
#endif
#ifdef V8_USE_ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif // V8_USE_ADDRESS_SANITIZER
namespace v8 {
namespace base {
......@@ -407,6 +411,38 @@ class V8_BASE_EXPORT Thread {
DISALLOW_COPY_AND_ASSIGN(Thread);
};
// TODO(v8:10354): Make use of the stack utilities here in V8.
class V8_BASE_EXPORT Stack {
public:
// Gets the start of the stack of the current thread.
static void* GetStackStart();
// Returns the current stack top. Works correctly with ASAN and SafeStack.
// GetCurrentStackPosition() should not be inlined, because it works on stack
// frames if it were inlined into a function with a huge stack frame it would
// return an address significantly above the actual current stack position.
static V8_NOINLINE void* GetCurrentStackPosition();
// Translates an ASAN-based slot to a real stack slot if necessary.
static void* GetStackSlot(void* slot) {
#ifdef V8_USE_ADDRESS_SANITIZER
void* fake_stack = __asan_get_current_fake_stack();
if (fake_stack) {
void* fake_frame_start;
void* real_frame = __asan_addr_is_in_fake_stack(
fake_stack, slot, &fake_frame_start, nullptr);
if (real_frame) {
return reinterpret_cast<void*>(
reinterpret_cast<uintptr_t>(real_frame) +
(reinterpret_cast<uintptr_t>(slot) -
reinterpret_cast<uintptr_t>(fake_frame_start)));
}
}
#endif // V8_USE_ADDRESS_SANITIZER
return slot;
}
};
} // namespace base
} // namespace v8
......
......@@ -83,5 +83,18 @@ TEST_F(ThreadLocalStorageTest, DoTest) {
Join();
}
TEST(StackTest, GetStackStart) { EXPECT_NE(nullptr, Stack::GetStackStart()); }
TEST(StackTest, GetCurrentStackPosition) {
EXPECT_NE(nullptr, Stack::GetCurrentStackPosition());
}
TEST(StackTest, StackVariableInBounds) {
void* dummy;
ASSERT_GT(Stack::GetStackStart(), Stack::GetCurrentStackPosition());
EXPECT_GT(Stack::GetStackStart(), Stack::GetStackSlot(&dummy));
EXPECT_LT(Stack::GetCurrentStackPosition(), Stack::GetStackSlot(&dummy));
}
} // namespace base
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment