[ubsan] Fix numerical overflows in wasm

Mostly signed integer overflows, and a few cases of double
division by zero (which is defined by IEEE-754 to return
Infinity (or NaN for 0/0) but is UB in C++).

Bug: v8:3770
Change-Id: Id92725b0ac57cb357978124a3dc6f477430bc97d
Reviewed-on: https://chromium-review.googlesource.com/c/1403133
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58696}
This commit is contained in:
Jakob Kummerow 2019-01-10 12:47:08 +01:00 committed by Commit Bot
parent f9a858fc96
commit 40ac5a39fc
11 changed files with 116 additions and 79 deletions

View File

@ -12,6 +12,7 @@
#include "src/asmjs/asm-js.h"
#include "src/asmjs/asm-types.h"
#include "src/base/optional.h"
#include "src/base/overflowing-math.h"
#include "src/flags.h"
#include "src/parsing/scanner.h"
#include "src/wasm/wasm-limits.h"
@ -1564,7 +1565,8 @@ AsmType* AsmJsParser::UnaryExpression() {
if (CheckForUnsigned(&uvalue)) {
// TODO(bradnelson): was supposed to be 0x7FFFFFFF, check errata.
if (uvalue <= 0x80000000) {
current_function_builder_->EmitI32Const(-static_cast<int32_t>(uvalue));
current_function_builder_->EmitI32Const(
base::NegateWithWraparound(static_cast<int32_t>(uvalue)));
} else {
FAILn("Integer numeric literal out of range.");
}

View File

@ -2665,6 +2665,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
// Typecheck the topmost {num_returns} values on the stack.
if (num_returns == 0) return true;
// This line requires num_returns > 0.
Value* stack_values = &*(stack_.end() - num_returns);
for (uint32_t i = 0; i < num_returns; ++i) {
auto& val = stack_values[i];

View File

@ -233,13 +233,13 @@ uint32_t word64_popcnt_wrapper(Address data) {
uint32_t word32_rol_wrapper(Address data) {
uint32_t input = ReadUnalignedValue<uint32_t>(data);
uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
return (input << shift) | (input >> (32 - shift));
return (input << shift) | (input >> ((32 - shift) & 31));
}
uint32_t word32_ror_wrapper(Address data) {
uint32_t input = ReadUnalignedValue<uint32_t>(data);
uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
return (input >> shift) | (input << (32 - shift));
return (input >> shift) | (input << ((32 - shift) & 31));
}
void float64_pow_wrapper(Address data) {

View File

@ -8,6 +8,7 @@
#include "src/wasm/wasm-interpreter.h"
#include "src/assembler-inl.h"
#include "src/base/overflowing-math.h"
#include "src/boxed-float.h"
#include "src/compiler/wasm-compiler.h"
#include "src/conversions.h"
@ -289,23 +290,19 @@ inline int64_t ExecuteI64ShrS(int64_t a, int64_t b, TrapReason* trap) {
}
inline uint32_t ExecuteI32Ror(uint32_t a, uint32_t b, TrapReason* trap) {
uint32_t shift = (b & 0x1F);
return (a >> shift) | (a << (32 - shift));
return (a >> (b & 0x1F)) | (a << ((32 - b) & 0x1F));
}
inline uint32_t ExecuteI32Rol(uint32_t a, uint32_t b, TrapReason* trap) {
uint32_t shift = (b & 0x1F);
return (a << shift) | (a >> (32 - shift));
return (a << (b & 0x1F)) | (a >> ((32 - b) & 0x1F));
}
inline uint64_t ExecuteI64Ror(uint64_t a, uint64_t b, TrapReason* trap) {
uint32_t shift = (b & 0x3F);
return (a >> shift) | (a << (64 - shift));
return (a >> (b & 0x3F)) | (a << ((64 - b) & 0x3F));
}
inline uint64_t ExecuteI64Rol(uint64_t a, uint64_t b, TrapReason* trap) {
uint32_t shift = (b & 0x3F);
return (a << shift) | (a >> (64 - shift));
return (a << (b & 0x3F)) | (a >> ((64 - b) & 0x3F));
}
inline float ExecuteF32Min(float a, float b, TrapReason* trap) {
@ -1737,9 +1734,9 @@ class ThreadImpl {
BINOP_CASE(F32x4Mul, f32x4, float4, 4, a * b)
BINOP_CASE(F32x4Min, f32x4, float4, 4, a < b ? a : b)
BINOP_CASE(F32x4Max, f32x4, float4, 4, a > b ? a : b)
BINOP_CASE(I32x4Add, i32x4, int4, 4, a + b)
BINOP_CASE(I32x4Sub, i32x4, int4, 4, a - b)
BINOP_CASE(I32x4Mul, i32x4, int4, 4, a * b)
BINOP_CASE(I32x4Add, i32x4, int4, 4, base::AddWithWraparound(a, b))
BINOP_CASE(I32x4Sub, i32x4, int4, 4, base::SubWithWraparound(a, b))
BINOP_CASE(I32x4Mul, i32x4, int4, 4, base::MulWithWraparound(a, b))
BINOP_CASE(I32x4MinS, i32x4, int4, 4, a < b ? a : b)
BINOP_CASE(I32x4MinU, i32x4, int4, 4,
static_cast<uint32_t>(a) < static_cast<uint32_t>(b) ? a : b)
@ -1749,9 +1746,9 @@ class ThreadImpl {
BINOP_CASE(S128And, i32x4, int4, 4, a & b)
BINOP_CASE(S128Or, i32x4, int4, 4, a | b)
BINOP_CASE(S128Xor, i32x4, int4, 4, a ^ b)
BINOP_CASE(I16x8Add, i16x8, int8, 8, a + b)
BINOP_CASE(I16x8Sub, i16x8, int8, 8, a - b)
BINOP_CASE(I16x8Mul, i16x8, int8, 8, a * b)
BINOP_CASE(I16x8Add, i16x8, int8, 8, base::AddWithWraparound(a, b))
BINOP_CASE(I16x8Sub, i16x8, int8, 8, base::SubWithWraparound(a, b))
BINOP_CASE(I16x8Mul, i16x8, int8, 8, base::MulWithWraparound(a, b))
BINOP_CASE(I16x8MinS, i16x8, int8, 8, a < b ? a : b)
BINOP_CASE(I16x8MinU, i16x8, int8, 8,
static_cast<uint16_t>(a) < static_cast<uint16_t>(b) ? a : b)
@ -1762,9 +1759,9 @@ class ThreadImpl {
BINOP_CASE(I16x8AddSaturateU, i16x8, int8, 8, SaturateAdd<uint16_t>(a, b))
BINOP_CASE(I16x8SubSaturateS, i16x8, int8, 8, SaturateSub<int16_t>(a, b))
BINOP_CASE(I16x8SubSaturateU, i16x8, int8, 8, SaturateSub<uint16_t>(a, b))
BINOP_CASE(I8x16Add, i8x16, int16, 16, a + b)
BINOP_CASE(I8x16Sub, i8x16, int16, 16, a - b)
BINOP_CASE(I8x16Mul, i8x16, int16, 16, a * b)
BINOP_CASE(I8x16Add, i8x16, int16, 16, base::AddWithWraparound(a, b))
BINOP_CASE(I8x16Sub, i8x16, int16, 16, base::SubWithWraparound(a, b))
BINOP_CASE(I8x16Mul, i8x16, int16, 16, base::MulWithWraparound(a, b))
BINOP_CASE(I8x16MinS, i8x16, int16, 16, a < b ? a : b)
BINOP_CASE(I8x16MinU, i8x16, int16, 16,
static_cast<uint8_t>(a) < static_cast<uint8_t>(b) ? a : b)
@ -1792,12 +1789,12 @@ class ThreadImpl {
}
UNOP_CASE(F32x4Abs, f32x4, float4, 4, std::abs(a))
UNOP_CASE(F32x4Neg, f32x4, float4, 4, -a)
UNOP_CASE(F32x4RecipApprox, f32x4, float4, 4, 1.0f / a)
UNOP_CASE(F32x4RecipSqrtApprox, f32x4, float4, 4, 1.0f / std::sqrt(a))
UNOP_CASE(I32x4Neg, i32x4, int4, 4, -a)
UNOP_CASE(F32x4RecipApprox, f32x4, float4, 4, base::Recip(a))
UNOP_CASE(F32x4RecipSqrtApprox, f32x4, float4, 4, base::RecipSqrt(a))
UNOP_CASE(I32x4Neg, i32x4, int4, 4, base::NegateWithWraparound(a))
UNOP_CASE(S128Not, i32x4, int4, 4, ~a)
UNOP_CASE(I16x8Neg, i16x8, int8, 8, -a)
UNOP_CASE(I8x16Neg, i8x16, int16, 16, -a)
UNOP_CASE(I16x8Neg, i16x8, int8, 8, base::NegateWithWraparound(a))
UNOP_CASE(I8x16Neg, i8x16, int16, 16, base::NegateWithWraparound(a))
#undef UNOP_CASE
#define CMPOP_CASE(op, name, stype, out_stype, count, expr) \
case kExpr##op: { \

View File

@ -8,6 +8,7 @@
#include "src/api-natives.h"
#include "src/assert-scope.h"
#include "src/ast/ast.h"
#include "src/base/overflowing-math.h"
#include "src/execution.h"
#include "src/handles.h"
#include "src/heap/factory.h"
@ -1408,7 +1409,7 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
int64_t old_size = old_buffer->byte_length() / i::wasm::kWasmPageSize;
int64_t new_size64 = old_size + delta_size;
int64_t new_size64 = base::AddWithWraparound(old_size, delta_size);
if (delta_size < 0 || max_size64 < new_size64 || new_size64 < old_size) {
thrower.RangeError(new_size64 < old_size ? "trying to shrink memory"
: "maximum memory size exceeded");

View File

@ -5,6 +5,7 @@
#include <cstdint>
#include "src/assembler-inl.h"
#include "src/base/overflowing-math.h"
#include "src/objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "test/cctest/cctest.h"
@ -104,7 +105,9 @@ TEST(TestCWasmEntryArgPassing_int32) {
CWasmEntryArgTester<int32_t, int32_t> tester(
{// Return 2*<0> + 1.
WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
[](int32_t a) { return 2 * a + 1; });
[](int32_t a) {
return base::AddWithWraparound(base::MulWithWraparound(2, a), 1);
});
FOR_INT32_INPUTS(v) { tester.CheckCall(*v); }
}

View File

@ -8,6 +8,7 @@
#include "src/assembler-inl.h"
#include "src/base/bits.h"
#include "src/base/overflowing-math.h"
#include "src/objects-inl.h"
#include "test/cctest/cctest.h"
@ -53,7 +54,9 @@ WASM_EXEC_TEST(I64Add) {
WasmRunner<int64_t, int64_t, int64_t> r(execution_tier);
BUILD(r, WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i + *j, r.Call(*i, *j)); }
FOR_INT64_INPUTS(j) {
CHECK_EQ(base::AddWithWraparound(*i, *j), r.Call(*i, *j));
}
}
}
@ -75,7 +78,9 @@ WASM_EXEC_TEST(I64Sub) {
WasmRunner<int64_t, int64_t, int64_t> r(execution_tier);
BUILD(r, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) { CHECK_EQ(*i - *j, r.Call(*i, *j)); }
FOR_INT64_INPUTS(j) {
CHECK_EQ(base::SubWithWraparound(*i, *j), r.Call(*i, *j));
}
}
}
@ -94,7 +99,8 @@ WASM_EXEC_TEST(I64AddUseOnlyLowWord) {
WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(static_cast<int32_t>(*i + *j), r.Call(*i, *j));
CHECK_EQ(static_cast<int32_t>(base::AddWithWraparound(*i, *j)),
r.Call(*i, *j));
}
}
}
@ -105,7 +111,8 @@ WASM_EXEC_TEST(I64SubUseOnlyLowWord) {
WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(static_cast<int32_t>(*i - *j), r.Call(*i, *j));
CHECK_EQ(static_cast<int32_t>(base::SubWithWraparound(*i, *j)),
r.Call(*i, *j));
}
}
}
@ -116,7 +123,8 @@ WASM_EXEC_TEST(I64MulUseOnlyLowWord) {
WASM_I64_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(static_cast<int32_t>(*i * *j), r.Call(*i, *j));
CHECK_EQ(static_cast<int32_t>(base::MulWithWraparound(*i, *j)),
r.Call(*i, *j));
}
}
}
@ -127,7 +135,7 @@ WASM_EXEC_TEST(I64ShlUseOnlyLowWord) {
WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
int32_t expected = static_cast<int32_t>((*i) << (*j & 0x3F));
int32_t expected = static_cast<int32_t>(base::ShlWithWraparound(*i, *j));
CHECK_EQ(expected, r.Call(*i, *j));
}
}
@ -1230,7 +1238,8 @@ WASM_EXEC_TEST(I64ReinterpretF64) {
WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO)));
FOR_INT32_INPUTS(i) {
int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
int64_t expected = base::MulWithWraparound(static_cast<int64_t>(*i),
int64_t{0x300010001L});
r.builder().WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call());
}
@ -1255,7 +1264,8 @@ WASM_EXEC_TEST(F64ReinterpretI64) {
WASM_GET_LOCAL(0));
FOR_INT32_INPUTS(i) {
int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
int64_t expected = base::MulWithWraparound(static_cast<int64_t>(*i),
int64_t{0x300010001L});
CHECK_EQ(expected, r.Call(expected));
CHECK_EQ(expected, r.builder().ReadMemory<int64_t>(&memory[0]));
}

View File

@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <type_traits>
#include "src/assembler-inl.h"
#include "src/base/bits.h"
#include "src/base/overflowing-math.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/value-helper.h"
#include "test/cctest/wasm/wasm-run-utils.h"
@ -50,22 +53,29 @@ typedef int8_t (*Int8ShiftOp)(int8_t, int);
void RunWasm_##name##_Impl(LowerSimd lower_simd, ExecutionTier execution_tier)
// Generic expected value functions.
template <typename T>
template <typename T, typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
T Negate(T a) {
return -a;
}
template <typename T>
// For signed integral types, use base::AddWithWraparound.
template <typename T, typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
T Add(T a, T b) {
return a + b;
}
template <typename T>
// For signed integral types, use base::SubWithWraparound.
template <typename T, typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
T Sub(T a, T b) {
return a - b;
}
template <typename T>
// For signed integral types, use base::MulWithWraparound.
template <typename T, typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
T Mul(T a, T b) {
return a * b;
}
@ -243,16 +253,6 @@ T Sqrt(T a) {
return std::sqrt(a);
}
template <typename T>
T Recip(T a) {
return 1.0f / a;
}
template <typename T>
T RecipSqrt(T a) {
return 1.0f / std::sqrt(a);
}
} // namespace
#define WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lane_value, lane_index) \
@ -509,13 +509,13 @@ WASM_SIMD_TEST(F32x4Neg) {
static const float kApproxError = 0.01f;
WASM_SIMD_TEST(F32x4RecipApprox) {
RunF32x4UnOpTest(execution_tier, lower_simd, kExprF32x4RecipApprox, Recip,
kApproxError);
RunF32x4UnOpTest(execution_tier, lower_simd, kExprF32x4RecipApprox,
base::Recip, kApproxError);
}
WASM_SIMD_TEST(F32x4RecipSqrtApprox) {
RunF32x4UnOpTest(execution_tier, lower_simd, kExprF32x4RecipSqrtApprox,
RecipSqrt, kApproxError);
base::RecipSqrt, kApproxError);
}
void RunF32x4BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
@ -923,7 +923,8 @@ void RunI32x4UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
WASM_SIMD_TEST(I32x4Neg) {
RunI32x4UnOpTest(execution_tier, lower_simd, kExprI32x4Neg, Negate);
RunI32x4UnOpTest(execution_tier, lower_simd, kExprI32x4Neg,
base::NegateWithWraparound);
}
WASM_SIMD_TEST(S128Not) {
@ -950,15 +951,18 @@ void RunI32x4BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
WASM_SIMD_TEST(I32x4Add) {
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Add, Add);
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Add,
base::AddWithWraparound);
}
WASM_SIMD_TEST(I32x4Sub) {
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Sub, Sub);
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Sub,
base::SubWithWraparound);
}
WASM_SIMD_TEST(I32x4Mul) {
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Mul, Mul);
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Mul,
base::MulWithWraparound);
}
WASM_SIMD_TEST(I32x4MinS) {
@ -1143,7 +1147,8 @@ void RunI16x8UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
WASM_SIMD_TEST(I16x8Neg) {
RunI16x8UnOpTest(execution_tier, lower_simd, kExprI16x8Neg, Negate);
RunI16x8UnOpTest(execution_tier, lower_simd, kExprI16x8Neg,
base::NegateWithWraparound);
}
// Tests both signed and unsigned conversion from I32x4 (packing).
@ -1211,7 +1216,8 @@ void RunI16x8BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
WASM_SIMD_TEST(I16x8Add) {
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Add, Add);
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Add,
base::AddWithWraparound);
}
WASM_SIMD_TEST(I16x8AddSaturateS) {
@ -1220,7 +1226,8 @@ WASM_SIMD_TEST(I16x8AddSaturateS) {
}
WASM_SIMD_TEST(I16x8Sub) {
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Sub, Sub);
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Sub,
base::SubWithWraparound);
}
WASM_SIMD_TEST(I16x8SubSaturateS) {
@ -1229,7 +1236,8 @@ WASM_SIMD_TEST(I16x8SubSaturateS) {
}
WASM_SIMD_TEST(I16x8Mul) {
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Mul, Mul);
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Mul,
base::MulWithWraparound);
}
WASM_SIMD_TEST(I16x8MinS) {
@ -1369,7 +1377,8 @@ void RunI8x16UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
WASM_SIMD_TEST(I8x16Neg) {
RunI8x16UnOpTest(execution_tier, lower_simd, kExprI8x16Neg, Negate);
RunI8x16UnOpTest(execution_tier, lower_simd, kExprI8x16Neg,
base::NegateWithWraparound);
}
// Tests both signed and unsigned conversion from I16x8 (packing).
@ -1439,7 +1448,8 @@ void RunI8x16BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
WASM_SIMD_TEST(I8x16Add) {
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Add, Add);
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Add,
base::AddWithWraparound);
}
WASM_SIMD_TEST(I8x16AddSaturateS) {
@ -1448,7 +1458,8 @@ WASM_SIMD_TEST(I8x16AddSaturateS) {
}
WASM_SIMD_TEST(I8x16Sub) {
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Sub, Sub);
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Sub,
base::SubWithWraparound);
}
WASM_SIMD_TEST(I8x16SubSaturateS) {
@ -1549,7 +1560,8 @@ WASM_SIMD_TEST(I8x16LeU) {
}
WASM_SIMD_TEST(I8x16Mul) {
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Mul, Mul);
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Mul,
base::MulWithWraparound);
}
void RunI8x16ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,

View File

@ -7,6 +7,7 @@
#include <string.h>
#include "src/assembler-inl.h"
#include "src/base/overflowing-math.h"
#include "src/base/platform/elapsed-timer.h"
#include "src/utils.h"
#include "test/cctest/cctest.h"
@ -84,14 +85,14 @@ WASM_EXEC_TEST(Int32Add_P) {
WasmRunner<int32_t, int32_t> r(execution_tier);
// p0 + 13
BUILD(r, WASM_I32_ADD(WASM_I32V_1(13), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); }
FOR_INT32_INPUTS(i) { CHECK_EQ(base::AddWithWraparound(*i, 13), r.Call(*i)); }
}
WASM_EXEC_TEST(Int32Add_P_fallthru) {
WasmRunner<int32_t, int32_t> r(execution_tier);
// p0 + 13
BUILD(r, WASM_I32_ADD(WASM_I32V_1(13), WASM_GET_LOCAL(0)));
FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); }
FOR_INT32_INPUTS(i) { CHECK_EQ(base::AddWithWraparound(*i, 13), r.Call(*i)); }
}
static void RunInt32AddTest(ExecutionTier execution_tier, const byte* code,
@ -190,9 +191,9 @@ static void TestInt32Binop(ExecutionTier execution_tier, WasmOpcode opcode,
[](ctype a, ctype b) -> ctype { return expected; }); \
}
WASM_I32_BINOP_TEST(Add, int32_t, a + b)
WASM_I32_BINOP_TEST(Sub, int32_t, a - b)
WASM_I32_BINOP_TEST(Mul, int32_t, a* b)
WASM_I32_BINOP_TEST(Add, int32_t, base::AddWithWraparound(a, b))
WASM_I32_BINOP_TEST(Sub, int32_t, base::SubWithWraparound(a, b))
WASM_I32_BINOP_TEST(Mul, int32_t, base::MulWithWraparound(a, b))
WASM_I32_BINOP_TEST(DivS, int32_t,
(a == kMinInt && b == -1) || b == 0
? static_cast<int32_t>(0xDEADBEEF)
@ -206,8 +207,8 @@ WASM_I32_BINOP_TEST(Xor, int32_t, a ^ b)
WASM_I32_BINOP_TEST(Shl, int32_t, a << (b & 0x1F))
WASM_I32_BINOP_TEST(ShrU, uint32_t, a >> (b & 0x1F))
WASM_I32_BINOP_TEST(ShrS, int32_t, a >> (b & 0x1F))
WASM_I32_BINOP_TEST(Ror, uint32_t, (a >> (b & 0x1F)) | (a << (32 - (b & 0x1F))))
WASM_I32_BINOP_TEST(Rol, uint32_t, (a << (b & 0x1F)) | (a >> (32 - (b & 0x1F))))
WASM_I32_BINOP_TEST(Ror, uint32_t, (a >> (b & 0x1F)) | (a << ((32 - b) & 0x1F)))
WASM_I32_BINOP_TEST(Rol, uint32_t, (a << (b & 0x1F)) | (a >> ((32 - b) & 0x1F)))
WASM_I32_BINOP_TEST(Eq, int32_t, a == b)
WASM_I32_BINOP_TEST(Ne, int32_t, a != b)
WASM_I32_BINOP_TEST(LtS, int32_t, a < b)
@ -3298,9 +3299,11 @@ WASM_EXEC_TEST(I32SubOnDifferentRegisters) {
}
WASM_EXEC_TEST(I32MulOnDifferentRegisters) {
BinOpOnDifferentRegisters<int32_t>(
execution_tier, kWasmI32, ArrayVector(kSome32BitInputs), kExprI32Mul,
[](int32_t lhs, int32_t rhs, bool* trap) { return lhs * rhs; });
BinOpOnDifferentRegisters<int32_t>(execution_tier, kWasmI32,
ArrayVector(kSome32BitInputs), kExprI32Mul,
[](int32_t lhs, int32_t rhs, bool* trap) {
return base::MulWithWraparound(lhs, rhs);
});
}
WASM_EXEC_TEST(I32ShlOnDifferentRegisters) {
@ -3372,9 +3375,11 @@ WASM_EXEC_TEST(I64SubOnDifferentRegisters) {
}
WASM_EXEC_TEST(I64MulOnDifferentRegisters) {
BinOpOnDifferentRegisters<int64_t>(
execution_tier, kWasmI64, ArrayVector(kSome64BitInputs), kExprI64Mul,
[](int64_t lhs, int64_t rhs, bool* trap) { return lhs * rhs; });
BinOpOnDifferentRegisters<int64_t>(execution_tier, kWasmI64,
ArrayVector(kSome64BitInputs), kExprI64Mul,
[](int64_t lhs, int64_t rhs, bool* trap) {
return base::MulWithWraparound(lhs, rhs);
});
}
WASM_EXEC_TEST(I64ShlOnDifferentRegisters) {

View File

@ -5,6 +5,7 @@
#include <cstdint>
#include "src/assembler-inl.h"
#include "src/base/overflowing-math.h"
#include "src/objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "test/cctest/cctest.h"
@ -100,7 +101,9 @@ TEST(TestArgumentPassing_int32) {
WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
{// Call f2 with param <0>.
WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())},
[](int32_t a) { return 2 * a + 1; });
[](int32_t a) {
return base::AddWithWraparound(base::MulWithWraparound(2, a), 1);
});
FOR_INT32_INPUTS(v) { helper.CheckCall(*v); }
}

View File

@ -4,6 +4,7 @@
#include "test/unittests/test-utils.h"
#include "src/base/overflowing-math.h"
#include "src/objects-inl.h"
#include "src/wasm/decoder.h"
#include "test/common/wasm/wasm-macro-gen.h"
@ -475,7 +476,8 @@ TEST_F(DecoderTest, ReadU32v_Bits) {
// foreach length 1...32
for (int i = 1; i <= 32; i++) {
uint32_t val = kVals[v];
if (i < 32) val &= ((1 << i) - 1);
if (i < 32)
val &= base::SubWithWraparound(base::ShlWithWraparound(1, i), 1);
unsigned length = 1 + i / 7;
for (unsigned j = 0; j < kMaxSize; j++) {