chromium/v8/src/heap/base/stack.cc

// 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/sanitizer/asan.h"
#include "src/base/sanitizer/msan.h"
#include "src/heap/base/memory-tagging.h"
#include "src/base/sanitizer/tsan.h"

namespace heap::base {

// Function with architecture-specific implementation:
// Pushes all callee-saved registers to the stack and invokes the callback,
// passing the supplied pointers (stack and argument) and the intended stack
// marker.
extern "C" void PushAllRegistersAndIterateStack(
    Stack* stack, void* argument, Stack::IterateStackCallback callback);

// static
bool Stack::IsOnStack(const void* slot) {}

namespace {

#ifdef V8_USE_ADDRESS_SANITIZER
// No ASAN support as accessing fake frames otherwise results in
// "stack-use-after-scope" warnings.
DISABLE_ASAN
// No HW ASAN support as stack iteration constructs pointers from arbitrary
// memory which may e.g. lead to tag mismatches.
DISABLE_HWASAN
// No TSAN support as the stack may not be exclusively owned by the current
// thread, e.g., for interrupt handling. Atomic reads are not enough as the
// other thread may use a lock to synchronize the access.
DISABLE_TSAN
void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor,
                                     const Stack::Segment& segment,
                                     const 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 (!segment.asan_fake_stack) return;
  void* fake_frame_begin;
  void* fake_frame_end;
  void* real_stack_frame = __asan_addr_is_in_fake_stack(
      const_cast<void*>(segment.asan_fake_stack), const_cast<void*>(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 (segment.start >= real_stack_frame && real_stack_frame >= segment.top) {
      // Iterate the fake frame.
      for (const void* const* current =
               reinterpret_cast<const void* const*>(fake_frame_begin);
           current < fake_frame_end; ++current) {
        const void* address = *current;
        if (address == nullptr) continue;
        visitor->VisitPointer(address);
      }
    }
  }
}
#else
void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor,
                                     const Stack::Segment& segment,
                                     const void* address) {}
#endif  // V8_USE_ADDRESS_SANITIZER

void IteratePointersInUnsafeStackIfNecessary(StackVisitor* visitor,
                                             const Stack::Segment& segment) {}

// 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.
DISABLE_ASAN
// No HW ASAN support as stack iteration constructs pointers from arbitrary
// memory which may e.g. lead to tag mismatches.
DISABLE_HWASAN
// No TSAN support as the stack may not be exclusively owned by the current
// thread, e.g., for interrupt handling. Atomic reads are not enough as the
// other thread may use a lock to synchronize the access.
DISABLE_TSAN
void IteratePointersInStack(StackVisitor* visitor,
                            const Stack::Segment& segment) {}

}  // namespace

void Stack::IteratePointersForTesting(StackVisitor* visitor) {}

void Stack::IteratePointersUntilMarker(StackVisitor* visitor) const {}

void Stack::IterateBackgroundStacks(StackVisitor* visitor) const {}

#ifdef DEBUG
// static
bool Stack::IsOnCurrentStack(const void* ptr) {}
#endif  // DEBUG

void Stack::AddStackSegment(const void* start, const void* top) {}

void Stack::ClearStackSegments() {}

void Stack::TrampolineCallbackHelper(void* argument,
                                     IterateStackCallback callback) {}

}  // namespace heap::base