Commit a0e66bca authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[Liftoff][ia32] Handle overflow in memory offset

When generating a 64bit memory operation on ia32, we need to emit two
operations, one at {offset+4}, one at {offset}. The computation
{offset+4} can overflow, which is ok because
1) it won't be used for code generation later, and
2) the generated code will not be reached because the memory access is
   always out of bounds anyway.

R=ahaas@chromium.org

Bug: v8:7499, v8:6600
Change-Id: Ia4660688c3291700c48efc201d15fc370b4dd854
Reviewed-on: https://chromium-review.googlesource.com/939389Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51604}
parent c7d01c42
...@@ -118,9 +118,10 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, ...@@ -118,9 +118,10 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Operand src_op = offset_reg == no_reg Operand src_op = offset_reg == no_reg
? Operand(src_addr, offset_imm) ? Operand(src_addr, offset_imm)
: Operand(src_addr, offset_reg, times_1, offset_imm); : Operand(src_addr, offset_reg, times_1, offset_imm);
// max_offset can overflow, but then is_uint31(offset_imm) is false and
// max_offset will not be used.
uint32_t max_offset = offset_imm + 4 * (type.value() == LoadType::kI64Load); uint32_t max_offset = offset_imm + 4 * (type.value() == LoadType::kI64Load);
DCHECK_LE(offset_imm, max_offset); // no overflow if (is_uint31(offset_imm) && is_uint31(max_offset)) {
if (max_offset > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
// The immediate(s) can not be encoded in the operand. Load the offset to a // The immediate(s) can not be encoded in the operand. Load the offset to a
// register first. // register first.
src = GetUnusedRegister(kGpReg, pinned).gp(); src = GetUnusedRegister(kGpReg, pinned).gp();
...@@ -182,7 +183,7 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, ...@@ -182,7 +183,7 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
? Operand(src_addr, offset_imm + 4) ? Operand(src_addr, offset_imm + 4)
: Operand(src_addr, offset_reg, times_1, offset_imm + 4); : Operand(src_addr, offset_reg, times_1, offset_imm + 4);
if (src != no_reg) { if (src != no_reg) {
src_op = Operand(src_addr, src, times_1, 4); upper_src_op = Operand(src_addr, src, times_1, 4);
} }
// The high word has to be mov'ed first, such that this is the protected // The high word has to be mov'ed first, such that this is the protected
// instruction. The mov of the low word cannot segfault. // instruction. The mov of the low word cannot segfault.
...@@ -210,9 +211,10 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, ...@@ -210,9 +211,10 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
Operand dst_op = offset_reg == no_reg Operand dst_op = offset_reg == no_reg
? Operand(dst_addr, offset_imm) ? Operand(dst_addr, offset_imm)
: Operand(dst_addr, offset_reg, times_1, offset_imm); : Operand(dst_addr, offset_reg, times_1, offset_imm);
// max_offset can overflow, but then is_uint31(offset_imm) is false and
// max_offset will not be used.
uint32_t max_offset = offset_imm + 4 * (type.value() == StoreType::kI64Store); uint32_t max_offset = offset_imm + 4 * (type.value() == StoreType::kI64Store);
DCHECK_LE(offset_imm, max_offset); // no overflow if (is_uint31(offset_imm) && is_uint31(max_offset)) {
if (max_offset > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
// The immediate(s) can not be encoded in the operand. Load the offset to a // The immediate(s) can not be encoded in the operand. Load the offset to a
// register first. // register first.
dst = pinned.set(GetUnusedRegister(kGpReg, pinned).gp()); dst = pinned.set(GetUnusedRegister(kGpReg, pinned).gp());
...@@ -257,7 +259,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, ...@@ -257,7 +259,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
? Operand(dst_addr, offset_imm + 4) ? Operand(dst_addr, offset_imm + 4)
: Operand(dst_addr, offset_reg, times_1, offset_imm + 4); : Operand(dst_addr, offset_reg, times_1, offset_imm + 4);
if (dst != no_reg) { if (dst != no_reg) {
dst_op = Operand(dst_addr, dst, times_1, 4); upper_dst_op = Operand(dst_addr, dst, times_1, 4);
} }
// The high word has to be mov'ed first, such that this is the protected // The high word has to be mov'ed first, such that this is the protected
// instruction. The mov of the low word cannot segfault. // instruction. The mov of the low word cannot segfault.
......
// Copyright 2018 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.
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder();
builder.addMemory(16, 32);
builder.addFunction(undefined, kSig_v_v).addBody([
kExprI32Const, 0, // i32.const 0
kExprI64LoadMem, 0, 0xff, 0xff, 0xff, 0xff,
0x0f, // i64.load align=0 offset=0xffffffff
kExprDrop, // drop
]);
builder.addExport('main', 0);
const module = builder.instantiate();
assertThrows(
() => module.exports.main(), WebAssembly.RuntimeError, /out of bounds/);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment