Reland "[wasm][mac][arm64] Enable OOB trap handler"

This is a reland of a80d51d488

There were two main issues:
- Liftoff did 32 bit addition to get the offset, which overflowed and
created a valid address where an OOB was expected
- The access mode and landing pad was missing for SIMD load and store
instructions
Also fixed the macros to disable trap handlers from simulator builds.

Original change's description:
> [wasm][mac][arm64] Enable OOB trap handler
>
> R=ahaas@chromium.org,mark@chromium.org,mseaborn@chromium.org
>
> Bug: v8:11098
> Change-Id: Ic4eb02a96805e49da71f301269567a6e0ac1b843
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2519555
> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
> Reviewed-by: Zhi An Ng <zhin@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Andreas Haas <ahaas@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#72136}

Bug: v8:11098
Change-Id: I2ebe434577f2cbe168f0bccf2936f69ca211e3c1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2637223
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Zhi An Ng <zhin@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72401}
This commit is contained in:
Thibaud Michaud 2021-01-28 11:54:20 +01:00 committed by Commit Bot
parent 0cd7979745
commit 5154f22c8c
7 changed files with 144 additions and 65 deletions

View File

@ -3806,6 +3806,13 @@ v8_source_set("v8_base_without_compiler") {
if (v8_control_flow_integrity) {
sources += [ "src/execution/arm64/pointer-authentication-arm64.h" ]
}
if (current_cpu == "arm64" && is_mac) {
sources += [
"src/trap-handler/handler-inside-posix.cc",
"src/trap-handler/handler-inside-posix.h",
"src/trap-handler/handler-outside-posix.cc",
]
}
if (is_win) {
sources += [
"src/diagnostics/unwinding-info-win64.cc",

View File

@ -5911,7 +5911,13 @@ bool v8::V8::Initialize(const int build_config) {
#if V8_OS_LINUX || V8_OS_MACOSX
bool TryHandleWebAssemblyTrapPosix(int sig_code, siginfo_t* info,
void* context) {
#if V8_TARGET_ARCH_X64 && !V8_OS_ANDROID
// When the target code runs on the V8 arm simulator, the trap handler does
// not behave as expected: the instruction pointer points inside the simulator
// code rather than the wasm code, so the trap handler cannot find the landing
// pad and lets the process crash. Therefore, only enable trap handlers if
// the host and target arch are the same.
#if (V8_TARGET_ARCH_X64 && !V8_OS_ANDROID) || \
(V8_HOST_ARCH_ARM64 && V8_TARGET_ARCH_ARM64 && V8_OS_MACOSX)
return i::trap_handler::TryHandleSignal(sig_code, info, context);
#else
return false;

View File

@ -375,6 +375,74 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
UNREACHABLE();
}
class WasmOutOfLineTrap : public OutOfLineCode {
public:
WasmOutOfLineTrap(CodeGenerator* gen, Instruction* instr)
: OutOfLineCode(gen), gen_(gen), instr_(instr) {}
void Generate() override {
Arm64OperandConverter i(gen_, instr_);
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
protected:
CodeGenerator* gen_;
void GenerateWithTrapId(TrapId trap_id) { GenerateCallToTrap(trap_id); }
private:
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
__ CallCFunction(ExternalReference::wasm_call_trap_callback_for_testing(),
0);
__ LeaveFrame(StackFrame::WASM);
auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
pop_count += (pop_count & 1); // align
__ Drop(pop_count);
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched when the code
// is added to the native module and copied into wasm code space.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
gen_->zone()->New<ReferenceMap>(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt);
__ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap);
}
}
Instruction* instr_;
};
class WasmProtectedInstructionTrap final : public WasmOutOfLineTrap {
public:
WasmProtectedInstructionTrap(CodeGenerator* gen, int pc, Instruction* instr)
: WasmOutOfLineTrap(gen, instr), pc_(pc) {}
void Generate() override {
gen_->AddProtectedInstructionLanding(pc_, __ pc_offset());
GenerateWithTrapId(TrapId::kTrapMemOutOfBounds);
}
private:
int pc_;
};
void EmitOOLTrapIfNeeded(Zone* zone, CodeGenerator* codegen,
InstructionCode opcode, Instruction* instr, int pc) {
const MemoryAccessMode access_mode =
static_cast<MemoryAccessMode>(MiscField::decode(opcode));
if (access_mode == kMemoryAccessProtected) {
zone->New<WasmProtectedInstructionTrap>(codegen, pc, instr);
}
}
void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
InstructionCode opcode, Instruction* instr,
Arm64OperandConverter const& i) {
@ -1697,39 +1765,49 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Fmov(i.OutputRegister(), i.InputDoubleRegister(0));
break;
case kArm64Ldrb:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldrb(i.OutputRegister(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64Ldrsb:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldrsb(i.OutputRegister(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64Strb:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Strb(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
break;
case kArm64Ldrh:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldrh(i.OutputRegister(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64Ldrsh:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldrsh(i.OutputRegister(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64Strh:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Strh(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
break;
case kArm64Ldrsw:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldrsw(i.OutputRegister(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64LdrW:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputRegister32(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64StrW:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Str(i.InputOrZeroRegister32(0), i.MemoryOperand(1));
break;
case kArm64Ldr:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputRegister(), i.MemoryOperand());
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
@ -1746,27 +1824,34 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
case kArm64Str:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Str(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
break;
case kArm64StrCompressTagged:
__ StoreTaggedField(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
break;
case kArm64LdrS:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
EmitMaybePoisonedFPLoad(this, opcode, &i, i.OutputDoubleRegister().S());
break;
case kArm64StrS:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Str(i.InputFloat32OrZeroRegister(0), i.MemoryOperand(1));
break;
case kArm64LdrD:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
EmitMaybePoisonedFPLoad(this, opcode, &i, i.OutputDoubleRegister());
break;
case kArm64StrD:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Str(i.InputFloat64OrZeroRegister(0), i.MemoryOperand(1));
break;
case kArm64LdrQ:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register(), i.MemoryOperand());
break;
case kArm64StrQ:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Str(i.InputSimd128Register(0), i.MemoryOperand(1));
break;
case kArm64DmbIsh:
@ -2664,58 +2749,69 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_UNOP_CASE(kArm64S8x4Reverse, Rev32, 16B);
SIMD_UNOP_CASE(kArm64S8x2Reverse, Rev16, 16B);
case kArm64LoadSplat: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
VectorFormat f = VectorFormatFillQ(LaneSizeField::decode(opcode));
__ ld1r(i.OutputSimd128Register().Format(f), i.MemoryOperand(0));
break;
}
case kArm64LoadLane: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
VectorFormat f = VectorFormatFillQ(LaneSizeField::decode(opcode));
int laneidx = i.InputInt8(1);
__ ld1(i.OutputSimd128Register().Format(f), laneidx, i.MemoryOperand(2));
break;
}
case kArm64StoreLane: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
VectorFormat f = VectorFormatFillQ(LaneSizeField::decode(opcode));
int laneidx = i.InputInt8(1);
__ st1(i.InputSimd128Register(0).Format(f), laneidx, i.MemoryOperand(2));
break;
}
case kArm64S128Load8x8S: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().V8B(), i.MemoryOperand(0));
__ Sxtl(i.OutputSimd128Register().V8H(), i.OutputSimd128Register().V8B());
break;
}
case kArm64S128Load8x8U: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().V8B(), i.MemoryOperand(0));
__ Uxtl(i.OutputSimd128Register().V8H(), i.OutputSimd128Register().V8B());
break;
}
case kArm64S128Load16x4S: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().V4H(), i.MemoryOperand(0));
__ Sxtl(i.OutputSimd128Register().V4S(), i.OutputSimd128Register().V4H());
break;
}
case kArm64S128Load16x4U: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().V4H(), i.MemoryOperand(0));
__ Uxtl(i.OutputSimd128Register().V4S(), i.OutputSimd128Register().V4H());
break;
}
case kArm64S128Load32x2S: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().V2S(), i.MemoryOperand(0));
__ Sxtl(i.OutputSimd128Register().V2D(), i.OutputSimd128Register().V2S());
break;
}
case kArm64S128Load32x2U: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().V2S(), i.MemoryOperand(0));
__ Uxtl(i.OutputSimd128Register().V2D(), i.OutputSimd128Register().V2S());
break;
}
case kArm64S128Load32Zero: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().S(), i.MemoryOperand(0));
break;
}
case kArm64S128Load64Zero: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
__ Ldr(i.OutputSimd128Register().D(), i.MemoryOperand(0));
break;
}
@ -2832,50 +2928,7 @@ void CodeGenerator::AssembleArchJump(RpoNumber target) {
void CodeGenerator::AssembleArchTrap(Instruction* instr,
FlagsCondition condition) {
class OutOfLineTrap final : public OutOfLineCode {
public:
OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
: OutOfLineCode(gen), instr_(instr), gen_(gen) {}
void Generate() final {
Arm64OperandConverter i(gen_, instr_);
TrapId trap_id =
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
GenerateCallToTrap(trap_id);
}
private:
void GenerateCallToTrap(TrapId trap_id) {
if (trap_id == TrapId::kInvalid) {
// We cannot test calls to the runtime in cctest/test-run-wasm.
// Therefore we emit a call to C here instead of a call to the runtime.
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(), 0);
__ LeaveFrame(StackFrame::WASM);
auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
int pop_count =
static_cast<int>(call_descriptor->StackParameterCount());
pop_count += (pop_count & 1); // align
__ Drop(pop_count);
__ Ret();
} else {
gen_->AssembleSourcePosition(instr_);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched when the code
// is added to the native module and copied into wasm code space.
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
ReferenceMap* reference_map =
gen_->zone()->New<ReferenceMap>(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
// The trap code should never return.
__ Brk(0);
}
}
}
Instruction* instr_;
CodeGenerator* gen_;
};
auto ool = zone()->New<OutOfLineTrap>(this, instr);
auto ool = zone()->New<WasmOutOfLineTrap>(this, instr);
Label* tlabel = ool->entry();
Condition cc = FlagsConditionToCondition(condition);
__ B(cc, tlabel);

View File

@ -673,6 +673,9 @@ void InstructionSelector::VisitLoadLane(Node* node) {
InstructionCode opcode = kArm64LoadLane;
opcode |= LaneSizeField::encode(params.rep.MemSize() * kBitsPerByte);
if (params.kind == MemoryAccessKind::kProtected) {
opcode |= AccessModeField::encode(kMemoryAccessProtected);
}
Arm64OperandGenerator g(this);
InstructionOperand addr = EmitAddBeforeLoadOrStore(this, node, &opcode);
@ -688,6 +691,9 @@ void InstructionSelector::VisitStoreLane(Node* node) {
InstructionCode opcode = kArm64StoreLane;
opcode |=
LaneSizeField::encode(ElementSizeInBytes(params.rep) * kBitsPerByte);
if (params.kind == MemoryAccessKind::kProtected) {
opcode |= AccessModeField::encode(kMemoryAccessProtected);
}
Arm64OperandGenerator g(this);
InstructionOperand addr = EmitAddBeforeLoadOrStore(this, node, &opcode);
@ -775,6 +781,9 @@ void InstructionSelector::VisitLoadTransform(Node* node) {
} else {
opcode |= AddressingModeField::encode(kMode_MRR);
}
if (params.kind == MemoryAccessKind::kProtected) {
opcode |= MiscField::encode(kMemoryAccessProtected);
}
Emit(opcode, 1, outputs, 2, inputs);
}
@ -847,16 +856,16 @@ void InstructionSelector::VisitLoad(Node* node) {
CHECK_NE(poisoning_level_, PoisoningMitigationLevel::kDontPoison);
opcode |= AccessModeField::encode(kMemoryAccessPoisoned);
}
if (node->opcode() == IrOpcode::kProtectedLoad) {
opcode |= MiscField::encode(kMemoryAccessProtected);
}
EmitLoad(this, node, opcode, immediate_mode, rep);
}
void InstructionSelector::VisitPoisonedLoad(Node* node) { VisitLoad(node); }
void InstructionSelector::VisitProtectedLoad(Node* node) {
// TODO(eholk)
UNIMPLEMENTED();
}
void InstructionSelector::VisitProtectedLoad(Node* node) { VisitLoad(node); }
void InstructionSelector::VisitStore(Node* node) {
Arm64OperandGenerator g(this);
@ -988,14 +997,15 @@ void InstructionSelector::VisitStore(Node* node) {
opcode |= AddressingModeField::encode(kMode_MRR);
}
if (node->opcode() == IrOpcode::kProtectedStore) {
opcode |= MiscField::encode(kMemoryAccessProtected);
}
Emit(opcode, 0, nullptr, input_count, inputs);
}
}
void InstructionSelector::VisitProtectedStore(Node* node) {
// TODO(eholk)
UNIMPLEMENTED();
}
void InstructionSelector::VisitProtectedStore(Node* node) { VisitStore(node); }
void InstructionSelector::VisitSimd128ReverseBytes(Node* node) {
UNREACHABLE();

View File

@ -106,20 +106,22 @@ bool TryHandleSignal(int signum, siginfo_t* info, void* context) {
SigUnmaskStack unmask(sigs);
ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
#if V8_OS_LINUX
auto* context_rip = &uc->uc_mcontext.gregs[REG_RIP];
#elif V8_OS_MACOSX
auto* context_rip = &uc->uc_mcontext->__ss.__rip;
#elif V8_OS_FREEBSD
auto* context_rip = &uc->uc_mcontext.mc_rip;
#if V8_OS_LINUX && V8_TARGET_ARCH_X64
auto* context_ip = &uc->uc_mcontext.gregs[REG_RIP];
#elif V8_OS_MACOSX && V8_TARGET_ARCH_ARM64
auto* context_ip = &uc->uc_mcontext->__ss.__pc;
#elif V8_OS_MACOSX && V8_TARGET_ARCH_X64
auto* context_ip = &uc->uc_mcontext->__ss.__rip;
#elif V8_OS_FREEBSD && V8_TARGET_ARCH_X64
auto* context_ip = &uc->uc_mcontext.mc_rip;
#else
#error Unsupported platform
#endif
uintptr_t fault_addr = *context_rip;
uintptr_t fault_addr = *context_ip;
uintptr_t landing_pad = 0;
if (TryFindLandingPad(fault_addr, &landing_pad)) {
// Tell the caller to return to the landing pad.
*context_rip = landing_pad;
*context_ip = landing_pad;
// We will return to wasm code, so restore the g_thread_in_wasm_code flag.
g_thread_in_wasm_code = true;
return true;

View File

@ -27,6 +27,8 @@ namespace trap_handler {
#define V8_TRAP_HANDLER_SUPPORTED true
#elif V8_TARGET_ARCH_X64 && V8_OS_FREEBSD
#define V8_TRAP_HANDLER_SUPPORTED true
#elif V8_HOST_ARCH_ARM64 && V8_TARGET_ARCH_ARM64 && V8_OS_MACOSX
#define V8_TRAP_HANDLER_SUPPORTED true
#else
#define V8_TRAP_HANDLER_SUPPORTED false
#endif

View File

@ -125,11 +125,10 @@ inline MemOperand GetMemOp(LiftoffAssembler* assm,
Register offset, T offset_imm) {
if (offset.is_valid()) {
if (offset_imm == 0) return MemOperand(addr.X(), offset.W(), UXTW);
Register tmp = temps->AcquireW();
// TODO(clemensb): Do a 64-bit addition if memory64 is used.
Register tmp = temps->AcquireX();
DCHECK_GE(kMaxUInt32, offset_imm);
assm->Add(tmp, offset.W(), offset_imm);
return MemOperand(addr.X(), tmp, UXTW);
assm->Add(tmp, offset.X(), offset_imm);
return MemOperand(addr.X(), tmp);
}
return MemOperand(addr.X(), offset_imm);
}