v8/test/unittests/wasm/trap-handler-simulator-unittest.cc
Clemens Backes b971ab3067 [traphandler] Fix test link errors on some MSan/ASan builds
Found these when compiling the arm64 simulator for MSan (Release) and
ASan (Debug and Release). Depending on the exact configuration (and
compiler), different functions will get inlined and different symbols
need to be available at link time.

1) Since GetRecoveredTrapCount is used in a unittest, it needs to be
   exported.

2) The thread-local g_thread_in_wasm_code cannot be exported on
   Windows, hence it cannot (safely) be used in unit tests. Use the
   {GetThreadInWasmThreadLocalAddress} function instead, which will
   return the address of that thread-local variable.

R=ahaas@chromium.org, mseaborn@chromium.org

Bug: v8:11955
Change-Id: I118f60c1580a8362f8232541576a1c41da7042bd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3049077
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75960}
2021-07-28 13:34:37 +00:00

126 lines
3.9 KiB
C++

// Copyright 2021 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/trap-handler/trap-handler-simulator.h"
#include "include/v8.h"
#include "src/codegen/macro-assembler-inl.h"
#include "src/execution/simulator.h"
#include "src/trap-handler/trap-handler.h"
#include "test/common/assembler-tester.h"
#include "test/unittests/test-utils.h"
#if !V8_HOST_ARCH_X64 || !V8_TARGET_ARCH_ARM64
#error "Only include this file on arm64 simulator builds on x64."
#endif
namespace v8 {
namespace internal {
namespace trap_handler {
constexpr uintptr_t kFakePc = 11;
class SimulatorTrapHandlerTest : public TestWithIsolate {
public:
void SetThreadInWasm() {
EXPECT_EQ(0, *thread_in_wasm);
*thread_in_wasm = 1;
}
void ResetThreadInWasm() {
EXPECT_EQ(1, *thread_in_wasm);
*thread_in_wasm = 0;
}
int* thread_in_wasm = trap_handler::GetThreadInWasmThreadLocalAddress();
};
TEST_F(SimulatorTrapHandlerTest, ProbeMemorySuccess) {
int x = 47;
EXPECT_EQ(0u, ProbeMemory(reinterpret_cast<uintptr_t>(&x), kFakePc));
}
TEST_F(SimulatorTrapHandlerTest, ProbeMemoryFail) {
constexpr uintptr_t kNullAddress = 0;
EXPECT_DEATH_IF_SUPPORTED(ProbeMemory(kNullAddress, kFakePc), "");
}
TEST_F(SimulatorTrapHandlerTest, ProbeMemoryFailWhileInWasm) {
// Test that we still crash if the trap handler is set up and the "thread in
// wasm" flag is set, but the PC is not registered as a protected instruction.
constexpr bool kUseDefaultHandler = true;
CHECK(v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultHandler));
constexpr uintptr_t kNullAddress = 0;
SetThreadInWasm();
EXPECT_DEATH_IF_SUPPORTED(ProbeMemory(kNullAddress, kFakePc), "");
}
TEST_F(SimulatorTrapHandlerTest, ProbeMemoryWithTrapHandled) {
constexpr uintptr_t kNullAddress = 0;
constexpr uintptr_t kFakeLandingPad = 19;
constexpr bool kUseDefaultHandler = true;
CHECK(v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultHandler));
ProtectedInstructionData fake_protected_instruction{kFakePc, kFakeLandingPad};
int handler_data_index =
RegisterHandlerData(0, 128, 1, &fake_protected_instruction);
SetThreadInWasm();
EXPECT_EQ(kFakeLandingPad, ProbeMemory(kNullAddress, kFakePc));
// Reset everything.
ResetThreadInWasm();
ReleaseHandlerData(handler_data_index);
RemoveTrapHandler();
}
TEST_F(SimulatorTrapHandlerTest, ProbeMemoryWithLandingPad) {
EXPECT_EQ(0u, GetRecoveredTrapCount());
// Test that the trap handler can recover a memory access violation in
// wasm code (we fake the wasm code and the access violation).
std::unique_ptr<TestingAssemblerBuffer> buffer = AllocateAssemblerBuffer();
constexpr Register scratch = x0;
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
// Generate an illegal memory access.
masm.Mov(scratch, 0);
uint32_t crash_offset = masm.pc_offset();
masm.Str(scratch, MemOperand(scratch, 0)); // nullptr access
uint32_t recovery_offset = masm.pc_offset();
// Return.
masm.Ret();
CodeDesc desc;
masm.GetCode(nullptr, &desc);
constexpr bool kUseDefaultHandler = true;
CHECK(v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultHandler));
ProtectedInstructionData protected_instruction{crash_offset, recovery_offset};
int handler_data_index =
RegisterHandlerData(reinterpret_cast<Address>(desc.buffer),
desc.instr_size, 1, &protected_instruction);
// Now execute the code.
buffer->MakeExecutable();
GeneratedCode<void> code = GeneratedCode<void>::FromAddress(
i_isolate(), reinterpret_cast<Address>(desc.buffer));
SetThreadInWasm();
code.Call();
ResetThreadInWasm();
ReleaseHandlerData(handler_data_index);
RemoveTrapHandler();
EXPECT_EQ(1u, GetRecoveredTrapCount());
}
} // namespace trap_handler
} // namespace internal
} // namespace v8