[ia32] Avoid signed overflow undefined behavior in InstructionSelector

Bug: chromium:1305925
Change-Id: I95dab2250ae60739a70c0d1f6ec30121d0ddcf8f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3537007
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79554}
This commit is contained in:
Tobias Tebbi 2022-03-18 17:25:18 +00:00 committed by V8 LUCI CQ
parent 857b33f537
commit ce8a10b9c4
3 changed files with 39 additions and 2 deletions

View File

@ -329,6 +329,16 @@ inline uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs) {
return rhs ? lhs % rhs : 0u;
}
// Wraparound integer arithmetic without undefined behavior.
inline int32_t WraparoundAdd32(int32_t lhs, int32_t rhs) {
return static_cast<int32_t>(static_cast<uint32_t>(lhs) +
static_cast<uint32_t>(rhs));
}
inline int32_t WraparoundNeg32(int32_t x) {
return static_cast<int32_t>(-static_cast<uint32_t>(x));
}
// SignedSaturatedAdd64(lhs, rhs) adds |lhs| and |rhs|,
// checks and returns the result.

View File

@ -9,6 +9,7 @@
#include <type_traits>
#include <vector>
#include "src/base/bits.h"
#include "src/base/flags.h"
#include "src/base/iterator.h"
#include "src/base/logging.h"
@ -132,11 +133,12 @@ class IA32OperandGenerator final : public OperandGenerator {
size_t* input_count, RegisterMode register_mode = kRegister) {
AddressingMode mode = kMode_MRI;
if (displacement_mode == kNegativeDisplacement) {
displacement = -displacement;
displacement = base::bits::WraparoundNeg32(displacement);
}
if (base != nullptr) {
if (base->opcode() == IrOpcode::kInt32Constant) {
displacement += OpParameter<int32_t>(base->op());
displacement = base::bits::WraparoundAdd32(
displacement, OpParameter<int32_t>(base->op()));
base = nullptr;
}
}

View File

@ -901,6 +901,31 @@ TEST_F(InstructionSelectorTest, SIMDSplatZero) {
}
}
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(1U, s.size());
EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
EXPECT_EQ(2147457600,
ImmediateOperand::cast(s[0]->InputAt(1))->inline_int32_value());
}
struct SwizzleConstants {
uint8_t shuffle[kSimd128Size];
bool omit_add;