[x64] Check negative displacement of min int32_t

With a displacement of int32_t min (-2^31), and a displacement mode of
kNegativeDisplacement, we will try to negate this constant, but the
result will not fit in an int32_t, leading to a runtime crash.

Check for this special case in CanBeImmediate, and return false.

Bug: chromium:1091892
Change-Id: I7f18153d13805f2836dd5c8e1bc098f1e9600566
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2341095
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Bill Budge <bbudge@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69311}
This commit is contained in:
Ng Zhi An 2020-08-07 10:04:22 -07:00 committed by Commit Bot
parent 242df3a2ed
commit 2fe9406998
2 changed files with 39 additions and 3 deletions

View File

@ -25,8 +25,12 @@ class X64OperandGenerator final : public OperandGenerator {
bool CanBeImmediate(Node* node) { bool CanBeImmediate(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kInt32Constant: case IrOpcode::kInt32Constant:
case IrOpcode::kRelocatableInt32Constant: case IrOpcode::kRelocatableInt32Constant: {
return true; const int32_t value = OpParameter<int32_t>(node->op());
// int32_t min will overflow if displacement mode is
// kNegativeDisplacement.
return value != std::numeric_limits<int32_t>::min();
}
case IrOpcode::kInt64Constant: { case IrOpcode::kInt64Constant: {
const int64_t value = OpParameter<int64_t>(node->op()); const int64_t value = OpParameter<int64_t>(node->op());
return std::numeric_limits<int32_t>::min() < value && return std::numeric_limits<int32_t>::min() < value &&

View File

@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include <limits>
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "test/unittests/compiler/backend/instruction-selector-unittest.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -976,6 +977,37 @@ TEST_F(InstructionSelectorTest, Int32AddScaled2Other) {
EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0))); EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
} }
TEST_F(InstructionSelectorTest, Int32AddMinNegativeDisplacement) {
// This test case is simplified from a Wasm fuzz test in
// https://crbug.com/1091892. The key here is that we match on a
// sequence like: Int32Add(Int32Sub(-524288, -2147483648), -26048), which
// matches on an EmitLea, with -2147483648 as the displacement. Since we
// have a Int32Sub node, it sets kNegativeDisplacement, and later we try to
// negate -2147483648, which overflows.
StreamBuilder m(this, MachineType::Int32());
Node* const c0 = m.Int32Constant(-524288);
Node* const c1 = m.Int32Constant(std::numeric_limits<int32_t>::min());
Node* const c2 = m.Int32Constant(-26048);
Node* const a0 = m.Int32Sub(c0, c1);
Node* const a1 = m.Int32Add(a0, c2);
m.Return(a1);
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kX64Sub32, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(s.ToVreg(c0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(c1), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
EXPECT_EQ(kX64Add32, s[1]->arch_opcode());
ASSERT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(kMode_None, s[1]->addressing_mode());
EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(0)));
EXPECT_TRUE(s[1]->InputAt(1)->IsImmediate());
EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Multiplication. // Multiplication.