diff options
Diffstat (limited to 'chromium/v8/src/heap/base/stack.cc')
| -rw-r--r-- | chromium/v8/src/heap/base/stack.cc | 129 |
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 |
