v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
stack.cc
Go to the documentation of this file.
1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <limits>
8
13
14namespace heap::base {
15
16// Function with architecture-specific implementation:
17// Pushes all callee-saved registers to the stack and invokes the callback,
18// passing the supplied pointers (stack and argument) and the intended stack
19// marker.
21 Stack* stack, void* argument, Stack::IterateStackCallback callback);
22
23// static
24bool Stack::IsOnStack(const void* slot) {
25#ifdef V8_USE_ADDRESS_SANITIZER
26 // If the slot is part of a fake frame, then it is definitely on the stack.
27 if (__asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(),
28 const_cast<void*>(slot), nullptr, nullptr)) {
29 return true;
30 }
31 // Fall through as there is still a regular stack present even when running
32 // with ASAN fake stacks.
33#endif // V8_USE_ADDRESS_SANITIZER
34#ifdef V8_USE_SAFE_STACK
35 if (__builtin___get_unsafe_stack_ptr() <= slot &&
36 slot <= __builtin___get_unsafe_stack_top()) {
37 return true;
38 }
39#endif // V8_USE_SAFE_STACK
42}
43
44namespace {
45
46#ifdef V8_USE_ADDRESS_SANITIZER
47// No ASAN support as accessing fake frames otherwise results in
48// "stack-use-after-scope" warnings.
50// No HW ASAN support as stack iteration constructs pointers from arbitrary
51// memory which may e.g. lead to tag mismatches.
53// No TSAN support as the stack may not be exclusively owned by the current
54// thread, e.g., for interrupt handling. Atomic reads are not enough as the
55// other thread may use a lock to synchronize the access.
57void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor,
58 const Stack::Segment& segment,
59 const void* address) {
60 // When using ASAN fake stack a pointer to the fake frame is kept on the
61 // native frame. In case |addr| points to a fake frame of the current stack
62 // iterate the fake frame. Frame layout see
63 // https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn
64 if (!segment.asan_fake_stack) return;
65 void* fake_frame_begin;
66 void* fake_frame_end;
67 void* real_stack_frame = __asan_addr_is_in_fake_stack(
68 const_cast<void*>(segment.asan_fake_stack), const_cast<void*>(address),
69 &fake_frame_begin, &fake_frame_end);
70 if (real_stack_frame) {
71 // |address| points to a fake frame. Check that the fake frame is part
72 // of this stack.
73 if (segment.start >= real_stack_frame && real_stack_frame >= segment.top) {
74 // Iterate the fake frame.
75 for (const void* const* current =
76 reinterpret_cast<const void* const*>(fake_frame_begin);
77 current < fake_frame_end; ++current) {
78 const void* address_curr = *current;
79 if (address_curr == nullptr) continue;
80 visitor->VisitPointer(address_curr);
81 }
82 }
83 }
84}
85#else
86void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor,
87 const Stack::Segment& segment,
88 const void* address) {}
89#endif // V8_USE_ADDRESS_SANITIZER
90
91void IteratePointersInUnsafeStackIfNecessary(StackVisitor* visitor,
92 const Stack::Segment& segment) {
93#ifdef V8_USE_SAFE_STACK
94 CHECK_NOT_NULL(segment.unsafe_stack_start);
95 CHECK_NOT_NULL(segment.unsafe_stack_top);
96 // Source:
97 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/safestack/safestack.cpp
98 constexpr size_t kSafeStackAlignmentBytes = 16;
99 CHECK_GE(segment.unsafe_stack_start, segment.unsafe_stack_top);
100 CHECK_EQ(0u, reinterpret_cast<uintptr_t>(segment.unsafe_stack_top) &
101 (kSafeStackAlignmentBytes - 1));
102 CHECK_EQ(0u, reinterpret_cast<uintptr_t>(segment.unsafe_stack_start) &
103 (kSafeStackAlignmentBytes - 1));
104
105 for (const void* const* current =
106 reinterpret_cast<const void* const*>(segment.unsafe_stack_top);
107 current < segment.unsafe_stack_start; ++current) {
108 const void* address_curr = *current;
109 if (address_curr == nullptr) continue;
110 visitor->VisitPointer(address_curr);
111 }
112#endif // V8_USE_SAFE_STACK
113}
114
115// This method should never be inlined to ensure that a possible redzone cannot
116// contain any data that needs to be scanned.
118// No ASAN support as method accesses redzones while walking the stack.
120// No HW ASAN support as stack iteration constructs pointers from arbitrary
121// memory which may e.g. lead to tag mismatches.
123// No TSAN support as the stack may not be exclusively owned by the current
124// thread, e.g., for interrupt handling. Atomic reads are not enough as the
125// other thread may use a lock to synchronize the access.
127void IteratePointersInStack(StackVisitor* visitor,
128 const Stack::Segment& segment) {
129 CHECK_NOT_NULL(segment.top);
130 CHECK_NOT_NULL(segment.start);
131 CHECK_GE(segment.start, segment.top);
132 // All supported platforms should have their stack aligned to at least
133 // sizeof(void*).
134 constexpr size_t kMinStackAlignment = sizeof(void*);
135 CHECK_EQ(0u,
136 reinterpret_cast<uintptr_t>(segment.top) & (kMinStackAlignment - 1));
137 CHECK_EQ(0u, reinterpret_cast<uintptr_t>(segment.start) &
138 (kMinStackAlignment - 1));
139
140 for (const void* const* current =
141 reinterpret_cast<const void* const*>(segment.top);
142 current < segment.start; ++current) {
143 // MSAN: Instead of unpoisoning the whole stack, the slot's value is copied
144 // into a local which is unpoisoned.
145 const void* address = *current;
146 MSAN_MEMORY_IS_INITIALIZED(&address, sizeof(address));
147 if (address == nullptr) {
148 continue;
149 }
150 visitor->VisitPointer(address);
151 IterateAsanFakeFrameIfNecessary(visitor, segment, address);
152 }
153}
154
155} // namespace
156
158 SetMarkerAndCallback([this, visitor]() { IteratePointers(visitor); });
159}
160
162 // Temporarily stop checking MTE tags whilst scanning the stack (whilst V8
163 // may not be tagging its portion of the stack, higher frames from the OS or
164 // libc could be using stack tagging.)
166 IteratePointersInStack(visitor, current_segment_);
167 IteratePointersInUnsafeStackIfNecessary(visitor, current_segment_);
170 }
171}
172
174 // Temporarily stop checking MTE tags whilst scanning the stack (whilst V8
175 // may not be tagging its portion of the stack, higher frames from the OS or
176 // libc could be using stack tagging.)
178
179 for (const auto& [_, segment] : background_stacks_) {
180 // All supported platforms should have their stack aligned to at least
181 // sizeof(void*).
182 constexpr size_t kMinStackAlignment = sizeof(void*);
183 CHECK_EQ(0u, reinterpret_cast<uintptr_t>(segment.top) &
184 (kMinStackAlignment - 1));
185 IteratePointersInStack(visitor, segment);
186 IteratePointersInUnsafeStackIfNecessary(visitor, segment);
187 }
188}
189
190#ifdef DEBUG
191// static
192bool Stack::IsOnCurrentStack(const void* ptr) {
193 DCHECK_NOT_NULL(ptr);
194 const void* current_stack_start = v8::base::Stack::GetStackStartUnchecked();
195 const void* current_stack_top = v8::base::Stack::GetCurrentStackPosition();
196 return ptr <= current_stack_start && ptr >= current_stack_top;
197}
198#endif // DEBUG
199
203 // TODO(chromium:1056170): Add support for SIMD and/or filtering.
204}
205
206} // namespace heap::base
#define DISABLE_HWASAN
Definition asan.h:90
#define DISABLE_ASAN
Definition asan.h:62
virtual void VisitPointer(const void *address)=0
void IteratePointersUntilMarker(StackVisitor *visitor) const
Definition stack.cc:161
Segment current_segment_
Definition stack.h:212
static bool IsOnStack(const void *slot)
Definition stack.cc:24
void(*)(Stack *, void *, const void *) IterateStackCallback
Definition stack.h:95
StackVisitorCallback scan_simulator_callback_
Definition stack.h:217
V8_NOINLINE void TrampolineCallbackHelper(void *argument, IterateStackCallback callback)
Definition stack.cc:200
void IteratePointers(StackVisitor *visitor) const
Definition stack.h:53
void IterateBackgroundStacks(StackVisitor *visitor) const
Definition stack.cc:173
void IteratePointersForTesting(StackVisitor *visitor)
Definition stack.cc:157
V8_INLINE void SetMarkerAndCallback(Callback callback)
Definition stack.h:68
std::map< ThreadId, Segment > background_stacks_
Definition stack.h:215
static StackSlot GetStackStartUnchecked()
Definition platform.cc:18
static V8_NOINLINE StackSlot GetCurrentStackPosition()
LineAndColumn current
TNode< Object > callback
#define _
#define MSAN_MEMORY_IS_INITIALIZED(start, size)
Definition msan.h:37
int s
Definition mul-fft.cc:297
void PushAllRegistersAndIterateStack(const Stack *sp, StackVisitor *sv, IterateStackCallback callback)
#define CHECK_GE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_NOT_NULL(val)
#define CHECK_EQ(lhs, rhs)
#define DISABLE_TSAN
Definition tsan.h:16
#define V8_NOINLINE
Definition v8config.h:586