summaryrefslogtreecommitdiffstats
path: root/chromium/v8/src/heap/base/stack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/heap/base/stack.cc')
-rw-r--r--chromium/v8/src/heap/base/stack.cc129
1 files changed, 129 insertions, 0 deletions
diff --git a/chromium/v8/src/heap/base/stack.cc b/chromium/v8/src/heap/base/stack.cc
new file mode 100644
index 00000000000..cd284444747
--- /dev/null
+++ b/chromium/v8/src/heap/base/stack.cc
@@ -0,0 +1,129 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/heap/base/stack.h"
+
+#include <limits>
+
+#include "src/base/platform/platform.h"
+#include "src/heap/cppgc/globals.h"
+#include "src/heap/cppgc/sanitizers.h"
+
+namespace heap {
+namespace base {
+
+using IterateStackCallback = void (*)(const Stack*, StackVisitor*, intptr_t*);
+extern "C" void PushAllRegistersAndIterateStack(const Stack*, StackVisitor*,
+ IterateStackCallback);
+
+Stack::Stack(const void* stack_start) : stack_start_(stack_start) {}
+
+bool Stack::IsOnStack(void* slot) const {
+ void* raw_slot = v8::base::Stack::GetStackSlot(slot);
+ return v8::base::Stack::GetCurrentStackPosition() <= raw_slot &&
+ raw_slot <= stack_start_;
+}
+
+namespace {
+
+#ifdef V8_USE_ADDRESS_SANITIZER
+
+// No ASAN support as accessing fake frames otherwise results in
+// "stack-use-after-scope" warnings.
+NO_SANITIZE_ADDRESS
+void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor,
+ void* asan_fake_stack,
+ const void* stack_start,
+ const void* stack_end, void* address) {
+ // When using ASAN fake stack a pointer to the fake frame is kept on the
+ // native frame. In case |addr| points to a fake frame of the current stack
+ // iterate the fake frame. Frame layout see
+ // https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn
+ if (asan_fake_stack) {
+ void* fake_frame_begin;
+ void* fake_frame_end;
+ void* real_stack_frame = __asan_addr_is_in_fake_stack(
+ asan_fake_stack, address, &fake_frame_begin, &fake_frame_end);
+ if (real_stack_frame) {
+ // |address| points to a fake frame. Check that the fake frame is part
+ // of this stack.
+ if (stack_start >= real_stack_frame && real_stack_frame >= stack_end) {
+ // Iterate the fake frame.
+ for (void** current = reinterpret_cast<void**>(fake_frame_begin);
+ current < fake_frame_end; ++current) {
+ void* addr = *current;
+ if (addr == nullptr) continue;
+ visitor->VisitPointer(addr);
+ }
+ }
+ }
+ }
+}
+
+#endif // V8_USE_ADDRESS_SANITIZER
+
+void IterateSafeStackIfNecessary(StackVisitor* visitor) {
+#if defined(__has_feature)
+#if __has_feature(safe_stack)
+ // Source:
+ // https://github.com/llvm/llvm-project/blob/master/compiler-rt/lib/safestack/safestack.cpp
+ constexpr size_t kSafeStackAlignmentBytes = 16;
+ void* stack_end = __builtin___get_unsafe_stack_ptr();
+ void* stack_start = __builtin___get_unsafe_stack_top();
+ CHECK_GT(stack_start, stack_end);
+ CHECK_EQ(0u, reinterpret_cast<uintptr_t>(stack_end) &
+ (kSafeStackAlignmentBytes - 1));
+ CHECK_EQ(0u, reinterpret_cast<uintptr_t>(stack_start) &
+ (kSafeStackAlignmentBytes - 1));
+ void** current = reinterpret_cast<void**>(stack_end);
+ for (; current < stack_start; ++current) {
+ void* address = *current;
+ if (address == nullptr) continue;
+ visitor->VisitPointer(address);
+ }
+#endif // __has_feature(safe_stack)
+#endif // defined(__has_feature)
+}
+
+// Called by the trampoline that pushes registers on the stack. This method
+// should never be inlined to ensure that a possible redzone cannot contain
+// any data that needs to be scanned.
+V8_NOINLINE
+// No ASAN support as method accesses redzones while walking the stack.
+NO_SANITIZE_ADDRESS
+void IteratePointersImpl(const Stack* stack, StackVisitor* visitor,
+ intptr_t* stack_end) {
+#ifdef V8_USE_ADDRESS_SANITIZER
+ void* asan_fake_stack = __asan_get_current_fake_stack();
+#endif // V8_USE_ADDRESS_SANITIZER
+ // All supported platforms should have their stack aligned to at least
+ // sizeof(void*).
+ constexpr size_t kMinStackAlignment = sizeof(void*);
+ void** current = reinterpret_cast<void**>(stack_end);
+ CHECK_EQ(0u, reinterpret_cast<uintptr_t>(current) & (kMinStackAlignment - 1));
+ for (; current < stack->stack_start(); ++current) {
+ // MSAN: Instead of unpoisoning the whole stack, the slot's value is copied
+ // into a local which is unpoisoned.
+ void* address = *current;
+ MSAN_UNPOISON(&address, sizeof(address));
+ if (address == nullptr) continue;
+ visitor->VisitPointer(address);
+#ifdef V8_USE_ADDRESS_SANITIZER
+ IterateAsanFakeFrameIfNecessary(visitor, asan_fake_stack,
+ stack->stack_start(), stack_end, address);
+#endif // V8_USE_ADDRESS_SANITIZER
+ }
+}
+
+} // namespace
+
+void Stack::IteratePointers(StackVisitor* visitor) const {
+ PushAllRegistersAndIterateStack(this, visitor, &IteratePointersImpl);
+ // No need to deal with callee-saved registers as they will be kept alive by
+ // the regular conservative stack iteration.
+ IterateSafeStackIfNecessary(visitor);
+}
+
+} // namespace base
+} // namespace heap