From f7e4689061261fb00660309c7778c124ff0ecca7 Mon Sep 17 00:00:00 2001 From: Benedikt Meurer Date: Fri, 19 Dec 2014 13:53:13 +0100 Subject: [PATCH] [turbofan] Fix unsafe out-of-bounds check for checked loads/stores. BUG=chromium:443744 LOG=y TEST=mjsunit/compiler/regress-443744 R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/804993004 Cr-Commit-Position: refs/heads/master@{#25901} --- src/compiler/arm64/code-generator-arm64.cc | 94 ++--- .../arm64/instruction-selector-arm64.cc | 12 +- src/compiler/x64/code-generator-x64.cc | 356 ++++++++---------- test/mjsunit/compiler/regress-443744.js | 14 + 4 files changed, 233 insertions(+), 243 deletions(-) create mode 100644 test/mjsunit/compiler/regress-443744.js diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index cc46fd677..e02523605 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc @@ -176,9 +176,9 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter { namespace { -class OutOfLineLoadFloat32 FINAL : public OutOfLineCode { +class OutOfLineLoadNaN32 FINAL : public OutOfLineCode { public: - OutOfLineLoadFloat32(CodeGenerator* gen, DoubleRegister result) + OutOfLineLoadNaN32(CodeGenerator* gen, DoubleRegister result) : OutOfLineCode(gen), result_(result) {} void Generate() FINAL { @@ -190,9 +190,9 @@ class OutOfLineLoadFloat32 FINAL : public OutOfLineCode { }; -class OutOfLineLoadFloat64 FINAL : public OutOfLineCode { +class OutOfLineLoadNaN64 FINAL : public OutOfLineCode { public: - OutOfLineLoadFloat64(CodeGenerator* gen, DoubleRegister result) + OutOfLineLoadNaN64(CodeGenerator* gen, DoubleRegister result) : OutOfLineCode(gen), result_(result) {} void Generate() FINAL { @@ -204,9 +204,9 @@ class OutOfLineLoadFloat64 FINAL : public OutOfLineCode { }; -class OutOfLineLoadInteger FINAL : public OutOfLineCode { +class OutOfLineLoadZero FINAL : public OutOfLineCode { public: - OutOfLineLoadInteger(CodeGenerator* gen, Register result) + OutOfLineLoadZero(CodeGenerator* gen, Register result) : OutOfLineCode(gen), result_(result) {} void Generate() FINAL { __ Mov(result_, 0); } @@ -218,53 +218,59 @@ class OutOfLineLoadInteger FINAL : public OutOfLineCode { } // namespace -#define ASSEMBLE_CHECKED_LOAD_FLOAT(width) \ - do { \ - auto result = i.OutputFloat##width##Register(); \ - auto offset = i.InputRegister32(0); \ - auto length = i.InputOperand32(1); \ - __ Cmp(offset, length); \ - auto ool = new (zone()) OutOfLineLoadFloat##width(this, result); \ - __ B(hs, ool->entry()); \ - __ Ldr(result, i.MemoryOperand(2)); \ - __ Bind(ool->exit()); \ +#define ASSEMBLE_CHECKED_LOAD_FLOAT(width) \ + do { \ + auto result = i.OutputFloat##width##Register(); \ + auto buffer = i.InputRegister(0); \ + auto offset = i.InputRegister32(1); \ + auto length = i.InputOperand32(2); \ + __ Cmp(offset, length); \ + auto ool = new (zone()) OutOfLineLoadNaN##width(this, result); \ + __ B(hs, ool->entry()); \ + __ Ldr(result, MemOperand(buffer, offset, UXTW)); \ + __ Bind(ool->exit()); \ } while (0) -#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ - do { \ - auto result = i.OutputRegister32(); \ - auto offset = i.InputRegister32(0); \ - auto length = i.InputOperand32(1); \ - __ Cmp(offset, length); \ - auto ool = new (zone()) OutOfLineLoadInteger(this, result); \ - __ B(hs, ool->entry()); \ - __ asm_instr(result, i.MemoryOperand(2)); \ - __ Bind(ool->exit()); \ +#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ + do { \ + auto result = i.OutputRegister32(); \ + auto buffer = i.InputRegister(0); \ + auto offset = i.InputRegister32(1); \ + auto length = i.InputOperand32(2); \ + __ Cmp(offset, length); \ + auto ool = new (zone()) OutOfLineLoadZero(this, result); \ + __ B(hs, ool->entry()); \ + __ asm_instr(result, MemOperand(buffer, offset, UXTW)); \ + __ Bind(ool->exit()); \ } while (0) -#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \ - do { \ - auto offset = i.InputRegister32(0); \ - auto length = i.InputOperand32(1); \ - __ Cmp(offset, length); \ - Label done; \ - __ B(hs, &done); \ - __ Str(i.InputFloat##width##Register(2), i.MemoryOperand(3)); \ - __ Bind(&done); \ +#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \ + do { \ + auto buffer = i.InputRegister(0); \ + auto offset = i.InputRegister32(1); \ + auto length = i.InputOperand32(2); \ + auto value = i.InputFloat##width##Register(3); \ + __ Cmp(offset, length); \ + Label done; \ + __ B(hs, &done); \ + __ Str(value, MemOperand(buffer, offset, UXTW)); \ + __ Bind(&done); \ } while (0) -#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ - do { \ - auto offset = i.InputRegister32(0); \ - auto length = i.InputOperand32(1); \ - __ Cmp(offset, length); \ - Label done; \ - __ B(hs, &done); \ - __ asm_instr(i.InputRegister32(2), i.MemoryOperand(3)); \ - __ Bind(&done); \ +#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ + do { \ + auto buffer = i.InputRegister(0); \ + auto offset = i.InputRegister32(1); \ + auto length = i.InputOperand32(2); \ + auto value = i.InputRegister32(3); \ + __ Cmp(offset, length); \ + Label done; \ + __ B(hs, &done); \ + __ asm_instr(value, MemOperand(buffer, offset, UXTW)); \ + __ Bind(&done); \ } while (0) diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index ee493cb75..72661af4c 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc @@ -390,10 +390,8 @@ void InstructionSelector::VisitCheckedLoad(Node* node) { UNREACHABLE(); return; } - InstructionOperand* offset_operand = g.UseRegister(offset); - Emit(opcode | AddressingModeField::encode(kMode_MRR), - g.DefineAsRegister(node), offset_operand, g.UseRegister(length), - g.UseRegister(buffer), offset_operand); + Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer), + g.UseRegister(offset), g.UseOperand(length, kArithmeticImm)); } @@ -425,10 +423,8 @@ void InstructionSelector::VisitCheckedStore(Node* node) { UNREACHABLE(); return; } - InstructionOperand* offset_operand = g.UseRegister(offset); - Emit(opcode | AddressingModeField::encode(kMode_MRR), nullptr, offset_operand, - g.UseRegister(length), g.UseRegister(value), g.UseRegister(buffer), - offset_operand); + Emit(opcode, nullptr, g.UseRegister(buffer), g.UseRegister(offset), + g.UseOperand(length, kArithmeticImm), g.UseRegister(value)); } diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 84b88f249..40f3247fd 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -272,9 +272,62 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode { } while (0) -#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \ +#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \ + do { \ + auto result = i.OutputDoubleRegister(); \ + auto buffer = i.InputRegister(0); \ + auto index1 = i.InputRegister(1); \ + auto index2 = i.InputInt32(2); \ + OutOfLineCode* ool; \ + if (instr->InputAt(3)->IsRegister()) { \ + auto length = i.InputRegister(3); \ + DCHECK_EQ(0, index2); \ + __ cmpl(index1, length); \ + ool = new (zone()) OutOfLineLoadNaN(this, result); \ + } else { \ + auto length = i.InputInt32(3); \ + DCHECK_LE(index2, length); \ + __ cmpq(index1, Immediate(length - index2)); \ + class OutOfLineLoadFloat FINAL : public OutOfLineCode { \ + public: \ + OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result, \ + Register buffer, Register index1, int32_t index2, \ + int32_t length) \ + : OutOfLineCode(gen), \ + result_(result), \ + buffer_(buffer), \ + index1_(index1), \ + index2_(index2), \ + length_(length) {} \ + \ + void Generate() FINAL { \ + __ leal(kScratchRegister, Operand(index1_, index2_)); \ + __ pcmpeqd(result_, result_); \ + __ cmpl(kScratchRegister, Immediate(length_)); \ + __ j(above_equal, exit()); \ + __ asm_instr(result_, \ + Operand(buffer_, kScratchRegister, times_1, 0)); \ + } \ + \ + private: \ + XMMRegister const result_; \ + Register const buffer_; \ + Register const index1_; \ + int32_t const index2_; \ + int32_t const length_; \ + }; \ + ool = new (zone()) \ + OutOfLineLoadFloat(this, result, buffer, index1, index2, length); \ + } \ + __ j(above_equal, ool->entry()); \ + __ asm_instr(result, Operand(buffer, index1, times_1, index2)); \ + __ bind(ool->exit()); \ + } while (false) + + +#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ do { \ - auto result = i.OutputDoubleRegister(); \ + auto result = i.OutputRegister(); \ auto buffer = i.InputRegister(0); \ auto index1 = i.InputRegister(1); \ auto index2 = i.InputInt32(2); \ @@ -283,46 +336,41 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode { auto length = i.InputRegister(3); \ DCHECK_EQ(0, index2); \ __ cmpl(index1, length); \ - ool = new (zone()) OutOfLineLoadNaN(this, result); \ + ool = new (zone()) OutOfLineLoadZero(this, result); \ } else { \ auto length = i.InputInt32(3); \ DCHECK_LE(index2, length); \ - __ cmpl(index1, Immediate(length - index2)); \ - if (index2 == 0) { \ - ool = new (zone()) OutOfLineLoadNaN(this, result); \ - } else { \ - class OutOfLineLoadFloat FINAL : public OutOfLineCode { \ - public: \ - OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result, \ + __ cmpq(index1, Immediate(length - index2)); \ + class OutOfLineLoadInteger FINAL : public OutOfLineCode { \ + public: \ + OutOfLineLoadInteger(CodeGenerator* gen, Register result, \ Register buffer, Register index1, int32_t index2, \ int32_t length) \ - : OutOfLineCode(gen), \ - result_(result), \ - buffer_(buffer), \ - index1_(index1), \ - index2_(index2), \ - length_(length) {} \ + : OutOfLineCode(gen), \ + result_(result), \ + buffer_(buffer), \ + index1_(index1), \ + index2_(index2), \ + length_(length) {} \ \ - void Generate() FINAL { \ - DCHECK_NE(0, index2_); \ - __ leal(kScratchRegister, Operand(index1_, index2_)); \ - __ pcmpeqd(result_, result_); \ - __ cmpl(kScratchRegister, Immediate(length_)); \ - __ j(above_equal, exit()); \ - __ asm_instr(result_, \ - Operand(buffer_, kScratchRegister, times_1, 0)); \ - } \ + void Generate() FINAL { \ + __ leal(kScratchRegister, Operand(index1_, index2_)); \ + __ xorl(result_, result_); \ + __ cmpl(kScratchRegister, Immediate(length_)); \ + __ j(above_equal, exit()); \ + __ asm_instr(result_, \ + Operand(buffer_, kScratchRegister, times_1, 0)); \ + } \ \ - private: \ - XMMRegister const result_; \ - Register const buffer_; \ - Register const index1_; \ - int32_t const index2_; \ - int32_t const length_; \ - }; \ - ool = new (zone()) \ - OutOfLineLoadFloat(this, result, buffer, index1, index2, length); \ - } \ + private: \ + Register const result_; \ + Register const buffer_; \ + Register const index1_; \ + int32_t const index2_; \ + int32_t const length_; \ + }; \ + ool = new (zone()) \ + OutOfLineLoadInteger(this, result, buffer, index1, index2, length); \ } \ __ j(above_equal, ool->entry()); \ __ asm_instr(result, Operand(buffer, index1, times_1, index2)); \ @@ -330,70 +378,65 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode { } while (false) -#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ - do { \ - auto result = i.OutputRegister(); \ - auto buffer = i.InputRegister(0); \ - auto index1 = i.InputRegister(1); \ - auto index2 = i.InputInt32(2); \ - OutOfLineCode* ool; \ - if (instr->InputAt(3)->IsRegister()) { \ - auto length = i.InputRegister(3); \ - DCHECK_EQ(0, index2); \ - __ cmpl(index1, length); \ - ool = new (zone()) OutOfLineLoadZero(this, result); \ - } else { \ - auto length = i.InputInt32(3); \ - DCHECK_LE(index2, length); \ - __ cmpl(index1, Immediate(length - index2)); \ - if (index2 == 0) { \ - ool = new (zone()) OutOfLineLoadZero(this, result); \ - } else { \ - class OutOfLineLoadInteger FINAL : public OutOfLineCode { \ - public: \ - OutOfLineLoadInteger(CodeGenerator* gen, Register result, \ - Register buffer, Register index1, \ - int32_t index2, int32_t length) \ - : OutOfLineCode(gen), \ - result_(result), \ - buffer_(buffer), \ - index1_(index1), \ - index2_(index2), \ - length_(length) {} \ - \ - void Generate() FINAL { \ - DCHECK_NE(0, index2_); \ - __ leal(kScratchRegister, Operand(index1_, index2_)); \ - __ xorl(result_, result_); \ - __ cmpl(kScratchRegister, Immediate(length_)); \ - __ j(above_equal, exit()); \ - __ asm_instr(result_, \ - Operand(buffer_, kScratchRegister, times_1, 0)); \ - } \ - \ - private: \ - Register const result_; \ - Register const buffer_; \ - Register const index1_; \ - int32_t const index2_; \ - int32_t const length_; \ - }; \ - ool = new (zone()) OutOfLineLoadInteger(this, result, buffer, index1, \ - index2, length); \ - } \ - } \ - __ j(above_equal, ool->entry()); \ - __ asm_instr(result, Operand(buffer, index1, times_1, index2)); \ - __ bind(ool->exit()); \ +#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \ + do { \ + auto buffer = i.InputRegister(0); \ + auto index1 = i.InputRegister(1); \ + auto index2 = i.InputInt32(2); \ + auto value = i.InputDoubleRegister(4); \ + if (instr->InputAt(3)->IsRegister()) { \ + auto length = i.InputRegister(3); \ + DCHECK_EQ(0, index2); \ + Label done; \ + __ cmpl(index1, length); \ + __ j(above_equal, &done, Label::kNear); \ + __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ + __ bind(&done); \ + } else { \ + auto length = i.InputInt32(3); \ + DCHECK_LE(index2, length); \ + __ cmpq(index1, Immediate(length - index2)); \ + class OutOfLineStoreFloat FINAL : public OutOfLineCode { \ + public: \ + OutOfLineStoreFloat(CodeGenerator* gen, Register buffer, \ + Register index1, int32_t index2, int32_t length, \ + XMMRegister value) \ + : OutOfLineCode(gen), \ + buffer_(buffer), \ + index1_(index1), \ + index2_(index2), \ + length_(length), \ + value_(value) {} \ + \ + void Generate() FINAL { \ + __ leal(kScratchRegister, Operand(index1_, index2_)); \ + __ cmpl(kScratchRegister, Immediate(length_)); \ + __ j(above_equal, exit()); \ + __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0), \ + value_); \ + } \ + \ + private: \ + Register const buffer_; \ + Register const index1_; \ + int32_t const index2_; \ + int32_t const length_; \ + XMMRegister const value_; \ + }; \ + auto ool = new (zone()) \ + OutOfLineStoreFloat(this, buffer, index1, index2, length, value); \ + __ j(above_equal, ool->entry()); \ + __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ + __ bind(ool->exit()); \ + } \ } while (false) -#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \ +#define ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Value) \ do { \ auto buffer = i.InputRegister(0); \ auto index1 = i.InputRegister(1); \ auto index2 = i.InputInt32(2); \ - auto value = i.InputDoubleRegister(4); \ if (instr->InputAt(3)->IsRegister()) { \ auto length = i.InputRegister(3); \ DCHECK_EQ(0, index2); \ @@ -405,112 +448,43 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode { } else { \ auto length = i.InputInt32(3); \ DCHECK_LE(index2, length); \ - __ cmpl(index1, Immediate(length - index2)); \ - if (index2 == 0) { \ - Label done; \ - __ j(above_equal, &done, Label::kNear); \ - __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ - __ bind(&done); \ - } else { \ - class OutOfLineStoreFloat FINAL : public OutOfLineCode { \ - public: \ - OutOfLineStoreFloat(CodeGenerator* gen, Register buffer, \ + __ cmpq(index1, Immediate(length - index2)); \ + class OutOfLineStoreInteger FINAL : public OutOfLineCode { \ + public: \ + OutOfLineStoreInteger(CodeGenerator* gen, Register buffer, \ Register index1, int32_t index2, int32_t length, \ - XMMRegister value) \ - : OutOfLineCode(gen), \ - buffer_(buffer), \ - index1_(index1), \ - index2_(index2), \ - length_(length), \ - value_(value) {} \ + Value value) \ + : OutOfLineCode(gen), \ + buffer_(buffer), \ + index1_(index1), \ + index2_(index2), \ + length_(length), \ + value_(value) {} \ \ - void Generate() FINAL { \ - DCHECK_NE(0, index2_); \ - __ leal(kScratchRegister, Operand(index1_, index2_)); \ - __ cmpl(kScratchRegister, Immediate(length_)); \ - __ j(above_equal, exit()); \ - __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0), \ - value_); \ - } \ + void Generate() FINAL { \ + __ leal(kScratchRegister, Operand(index1_, index2_)); \ + __ cmpl(kScratchRegister, Immediate(length_)); \ + __ j(above_equal, exit()); \ + __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0), \ + value_); \ + } \ \ - private: \ - Register const buffer_; \ - Register const index1_; \ - int32_t const index2_; \ - int32_t const length_; \ - XMMRegister const value_; \ - }; \ - auto ool = new (zone()) \ - OutOfLineStoreFloat(this, buffer, index1, index2, length, value); \ - __ j(above_equal, ool->entry()); \ - __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ - __ bind(ool->exit()); \ - } \ + private: \ + Register const buffer_; \ + Register const index1_; \ + int32_t const index2_; \ + int32_t const length_; \ + Value const value_; \ + }; \ + auto ool = new (zone()) \ + OutOfLineStoreInteger(this, buffer, index1, index2, length, value); \ + __ j(above_equal, ool->entry()); \ + __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ + __ bind(ool->exit()); \ } \ } while (false) -#define ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Value) \ - do { \ - auto buffer = i.InputRegister(0); \ - auto index1 = i.InputRegister(1); \ - auto index2 = i.InputInt32(2); \ - if (instr->InputAt(3)->IsRegister()) { \ - auto length = i.InputRegister(3); \ - DCHECK_EQ(0, index2); \ - Label done; \ - __ cmpl(index1, length); \ - __ j(above_equal, &done, Label::kNear); \ - __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ - __ bind(&done); \ - } else { \ - auto length = i.InputInt32(3); \ - DCHECK_LE(index2, length); \ - __ cmpl(index1, Immediate(length - index2)); \ - if (index2 == 0) { \ - Label done; \ - __ j(above_equal, &done, Label::kNear); \ - __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ - __ bind(&done); \ - } else { \ - class OutOfLineStoreInteger FINAL : public OutOfLineCode { \ - public: \ - OutOfLineStoreInteger(CodeGenerator* gen, Register buffer, \ - Register index1, int32_t index2, \ - int32_t length, Value value) \ - : OutOfLineCode(gen), \ - buffer_(buffer), \ - index1_(index1), \ - index2_(index2), \ - length_(length), \ - value_(value) {} \ - \ - void Generate() FINAL { \ - DCHECK_NE(0, index2_); \ - __ leal(kScratchRegister, Operand(index1_, index2_)); \ - __ cmpl(kScratchRegister, Immediate(length_)); \ - __ j(above_equal, exit()); \ - __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0), \ - value_); \ - } \ - \ - private: \ - Register const buffer_; \ - Register const index1_; \ - int32_t const index2_; \ - int32_t const length_; \ - Value const value_; \ - }; \ - auto ool = new (zone()) OutOfLineStoreInteger(this, buffer, index1, \ - index2, length, value); \ - __ j(above_equal, ool->entry()); \ - __ asm_instr(Operand(buffer, index1, times_1, index2), value); \ - __ bind(ool->exit()); \ - } \ - } \ - } while (false) - - #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ do { \ if (instr->InputAt(4)->IsRegister()) { \ diff --git a/test/mjsunit/compiler/regress-443744.js b/test/mjsunit/compiler/regress-443744.js new file mode 100644 index 000000000..5e7f3bc9d --- /dev/null +++ b/test/mjsunit/compiler/regress-443744.js @@ -0,0 +1,14 @@ +// Copyright 2014 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. + +var m = (function(stdlib, foreign, heap) { + "use asm"; + var MEM = new stdlib.Uint8Array(heap); + function f(x) { + x = x | 0; + MEM[x] = 0; + } + return {f: f}; +})(this, {}, new ArrayBuffer(1)); +m.f(-926416896 * 32 * 1024); -- 2.34.1