95cdb3c573
As Wasm module can live longer than the isolate that initially created them, it generally makes sense to use the WasmEngine's accounting allocator for the decoded WasmModule. Instead of passing that allocator through many functions, we can just get it directly from the one global WasmEngine when we need it. R=ahaas@chromium.org Change-Id: I552f8e19072f2305a3186b821c2f5b3969eac83f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4071464 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/main@{#84611}
3478 lines
136 KiB
C++
3478 lines
136 KiB
C++
// Copyright 2015 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.
|
|
|
|
#include "src/wasm/module-decoder.h"
|
|
|
|
#include "src/wasm/branch-hint-map.h"
|
|
#include "src/wasm/wasm-engine.h"
|
|
#include "src/wasm/wasm-features.h"
|
|
#include "src/wasm/wasm-limits.h"
|
|
#include "src/wasm/wasm-opcodes.h"
|
|
#include "test/common/wasm/flag-utils.h"
|
|
#include "test/common/wasm/wasm-macro-gen.h"
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gmock-support.h"
|
|
|
|
using testing::HasSubstr;
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
namespace module_decoder_unittest {
|
|
|
|
#define WASM_INIT_EXPR_I32V_1(val) WASM_I32V_1(val), kExprEnd
|
|
#define WASM_INIT_EXPR_I32V_2(val) WASM_I32V_2(val), kExprEnd
|
|
#define WASM_INIT_EXPR_I32V_3(val) WASM_I32V_3(val), kExprEnd
|
|
#define WASM_INIT_EXPR_I32V_4(val) WASM_I32V_4(val), kExprEnd
|
|
#define WASM_INIT_EXPR_I32V_5(val) WASM_I32V_5(val), kExprEnd
|
|
#define WASM_INIT_EXPR_F32(val) WASM_F32(val), kExprEnd
|
|
#define WASM_INIT_EXPR_I64(val) WASM_I64(val), kExprEnd
|
|
#define WASM_INIT_EXPR_F64(val) WASM_F64(val), kExprEnd
|
|
#define WASM_INIT_EXPR_EXTERN_REF_NULL WASM_REF_NULL(kExternRefCode), kExprEnd
|
|
#define WASM_INIT_EXPR_FUNC_REF_NULL WASM_REF_NULL(kFuncRefCode), kExprEnd
|
|
#define WASM_INIT_EXPR_REF_FUNC(val) WASM_REF_FUNC(val), kExprEnd
|
|
#define WASM_INIT_EXPR_GLOBAL(index) WASM_GLOBAL_GET(index), kExprEnd
|
|
#define WASM_INIT_EXPR_STRUCT_NEW(index, ...) \
|
|
WASM_STRUCT_NEW(index, __VA_ARGS__), kExprEnd
|
|
#define WASM_INIT_EXPR_ARRAY_NEW_FIXED(index, length, ...) \
|
|
WASM_ARRAY_NEW_FIXED(index, length, __VA_ARGS__), kExprEnd
|
|
|
|
#define REF_NULL_ELEMENT kExprRefNull, kFuncRefCode, kExprEnd
|
|
#define REF_FUNC_ELEMENT(v) kExprRefFunc, U32V_1(v), kExprEnd
|
|
|
|
#define EMPTY_BODY 0
|
|
#define NOP_BODY 2, 0, kExprNop
|
|
|
|
#define SIG_ENTRY_i_i SIG_ENTRY_x_x(kI32Code, kI32Code)
|
|
|
|
#define UNKNOWN_SECTION(size) 0, U32V_1(size + 5), ADD_COUNT('l', 'u', 'l', 'z')
|
|
#define TYPE_SECTION(count, ...) SECTION(Type, U32V_1(count), __VA_ARGS__)
|
|
#define FUNCTION_SECTION(count, ...) \
|
|
SECTION(Function, U32V_1(count), __VA_ARGS__)
|
|
|
|
#define FOO_STRING ADD_COUNT('f', 'o', 'o')
|
|
#define NO_LOCAL_NAMES 0
|
|
|
|
#define EMPTY_TYPE_SECTION SECTION(Type, ENTRY_COUNT(0))
|
|
#define EMPTY_FUNCTION_SECTION SECTION(Function, ENTRY_COUNT(0))
|
|
#define EMPTY_FUNCTION_BODIES_SECTION SECTION(Code, ENTRY_COUNT(0))
|
|
#define SECTION_NAMES(...) \
|
|
SECTION(Unknown, ADD_COUNT('n', 'a', 'm', 'e'), ##__VA_ARGS__)
|
|
#define EMPTY_NAMES_SECTION SECTION_NAMES()
|
|
#define SECTION_SRC_MAP(...) \
|
|
SECTION(Unknown, \
|
|
ADD_COUNT('s', 'o', 'u', 'r', 'c', 'e', 'M', 'a', 'p', 'p', 'i', \
|
|
'n', 'g', 'U', 'R', 'L'), \
|
|
ADD_COUNT(__VA_ARGS__))
|
|
#define SECTION_COMPILATION_HINTS(...) \
|
|
SECTION(Unknown, \
|
|
ADD_COUNT('c', 'o', 'm', 'p', 'i', 'l', 'a', 't', 'i', 'o', 'n', \
|
|
'H', 'i', 'n', 't', 's'), \
|
|
ADD_COUNT(__VA_ARGS__))
|
|
|
|
#define SECTION_BRANCH_HINTS(...) \
|
|
SECTION(Unknown, \
|
|
ADD_COUNT('m', 'e', 't', 'a', 'd', 'a', 't', 'a', '.', 'c', 'o', \
|
|
'd', 'e', '.', 'b', 'r', 'a', 'n', 'c', 'h', '_', 'h', \
|
|
'i', 'n', 't'), \
|
|
__VA_ARGS__)
|
|
|
|
#define X1(...) __VA_ARGS__
|
|
#define X2(...) __VA_ARGS__, __VA_ARGS__
|
|
#define X3(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__
|
|
#define X4(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__, __VA_ARGS__
|
|
|
|
#define ONE_EMPTY_FUNCTION(sig_index) \
|
|
SECTION(Function, ENTRY_COUNT(1), X1(sig_index))
|
|
|
|
#define TWO_EMPTY_FUNCTIONS(sig_index) \
|
|
SECTION(Function, ENTRY_COUNT(2), X2(sig_index))
|
|
|
|
#define THREE_EMPTY_FUNCTIONS(sig_index) \
|
|
SECTION(Function, ENTRY_COUNT(3), X3(sig_index))
|
|
|
|
#define FOUR_EMPTY_FUNCTIONS(sig_index) \
|
|
SECTION(Function, ENTRY_COUNT(4), X4(sig_index))
|
|
|
|
#define ONE_EMPTY_BODY SECTION(Code, ENTRY_COUNT(1), X1(EMPTY_BODY))
|
|
#define TWO_EMPTY_BODIES SECTION(Code, ENTRY_COUNT(2), X2(EMPTY_BODY))
|
|
#define THREE_EMPTY_BODIES SECTION(Code, ENTRY_COUNT(3), X3(EMPTY_BODY))
|
|
#define FOUR_EMPTY_BODIES SECTION(Code, ENTRY_COUNT(4), X4(EMPTY_BODY))
|
|
|
|
#define TYPE_SECTION_ONE_SIG_VOID_VOID \
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_v)
|
|
|
|
#define LINEAR_MEMORY_INDEX_0 0
|
|
|
|
#define EXCEPTION_ENTRY(sig_index) U32V_1(kExceptionAttribute), sig_index
|
|
|
|
#define FIELD_COUNT(count) U32V_1(count)
|
|
#define STRUCT_FIELD(type, mutability) type, (mutability ? 1 : 0)
|
|
#define WASM_REF(index) kRefCode, index
|
|
#define WASM_OPT_REF(index) kRefNullCode, index
|
|
#define WASM_STRUCT_DEF(...) kWasmStructTypeCode, __VA_ARGS__
|
|
#define WASM_ARRAY_DEF(type, mutability) \
|
|
kWasmArrayTypeCode, type, (mutability ? 1 : 0)
|
|
#define WASM_FUNCTION_DEF(...) kWasmFunctionTypeCode, __VA_ARGS__
|
|
|
|
#define EXPECT_VERIFIES(data) \
|
|
do { \
|
|
ModuleResult _result = DecodeModule(base::ArrayVector(data)); \
|
|
EXPECT_OK(_result); \
|
|
} while (false)
|
|
|
|
#define EXPECT_FAILURE_LEN(data, length) \
|
|
do { \
|
|
ModuleResult _result = DecodeModule(base::VectorOf(data, length)); \
|
|
EXPECT_FALSE(_result.ok()); \
|
|
} while (false)
|
|
|
|
#define EXPECT_FAILURE(data) EXPECT_FAILURE_LEN(data, sizeof(data))
|
|
|
|
#define EXPECT_FAILURE_WITH_MSG(data, msg) \
|
|
do { \
|
|
ModuleResult _result = DecodeModule(base::ArrayVector(data)); \
|
|
EXPECT_FALSE(_result.ok()); \
|
|
if (!_result.ok()) { \
|
|
EXPECT_THAT(_result.error().message(), HasSubstr(msg)); \
|
|
} \
|
|
} while (false)
|
|
|
|
#define EXPECT_OFF_END_FAILURE(data, min) \
|
|
do { \
|
|
static_assert(min < arraysize(data)); \
|
|
for (size_t _length = min; _length < arraysize(data); _length++) { \
|
|
EXPECT_FAILURE_LEN(data, _length); \
|
|
} \
|
|
} while (false)
|
|
|
|
#define EXPECT_OK(result) \
|
|
do { \
|
|
if (!result.ok()) { \
|
|
GTEST_NONFATAL_FAILURE_(result.error().message().c_str()); \
|
|
return; \
|
|
} \
|
|
} while (false)
|
|
|
|
#define EXPECT_NOT_OK(result, msg) \
|
|
do { \
|
|
EXPECT_FALSE(result.ok()); \
|
|
if (!result.ok()) { \
|
|
EXPECT_THAT(result.error().message(), HasSubstr(msg)); \
|
|
} \
|
|
} while (false)
|
|
|
|
static size_t SizeOfVarInt(size_t value) {
|
|
size_t size = 0;
|
|
do {
|
|
size++;
|
|
value = value >> 7;
|
|
} while (value > 0);
|
|
return size;
|
|
}
|
|
|
|
struct ValueTypePair {
|
|
uint8_t code;
|
|
ValueType type;
|
|
} kValueTypes[] = {
|
|
{kI32Code, kWasmI32}, // --
|
|
{kI64Code, kWasmI64}, // --
|
|
{kF32Code, kWasmF32}, // --
|
|
{kF64Code, kWasmF64}, // --
|
|
{kFuncRefCode, kWasmFuncRef}, // --
|
|
{kNoFuncCode, kWasmNullFuncRef}, // --
|
|
{kExternRefCode, kWasmExternRef}, // --
|
|
{kNoExternCode, kWasmNullExternRef}, // --
|
|
{kAnyRefCode, kWasmAnyRef}, // --
|
|
{kEqRefCode, kWasmEqRef}, // --
|
|
{kI31RefCode, kWasmI31Ref}, // --
|
|
{kStructRefCode, kWasmStructRef}, // --
|
|
{kArrayRefCode, kWasmArrayRef}, // --
|
|
{kNoneCode, kWasmNullRef}, // --
|
|
{kStringRefCode, kWasmStringRef}, // --
|
|
{kStringViewWtf8Code, kWasmStringViewWtf8}, // --
|
|
{kStringViewWtf16Code, kWasmStringViewWtf16}, // --
|
|
{kStringViewIterCode, kWasmStringViewIter}, // --
|
|
};
|
|
|
|
class WasmModuleVerifyTest : public TestWithIsolateAndZone {
|
|
public:
|
|
WasmFeatures enabled_features_ = WasmFeatures::None();
|
|
|
|
ModuleResult DecodeModule(base::Vector<const uint8_t> module_bytes) {
|
|
// Add the wasm magic and version number automatically.
|
|
size_t size = module_bytes.size();
|
|
byte header[] = {WASM_MODULE_HEADER};
|
|
size_t total = sizeof(header) + size;
|
|
auto temp = new byte[total];
|
|
memcpy(temp, header, sizeof(header));
|
|
if (size > 0) {
|
|
memcpy(temp + sizeof(header), module_bytes.begin(), size);
|
|
}
|
|
ModuleResult result = DecodeWasmModule(
|
|
enabled_features_, base::VectorOf(temp, total), false, kWasmOrigin);
|
|
delete[] temp;
|
|
return result;
|
|
}
|
|
ModuleResult DecodeModuleNoHeader(base::Vector<const uint8_t> bytes) {
|
|
return DecodeWasmModule(enabled_features_, bytes, false, kWasmOrigin);
|
|
}
|
|
};
|
|
|
|
TEST_F(WasmModuleVerifyTest, WrongMagic) {
|
|
for (uint32_t x = 1; x; x <<= 1) {
|
|
const byte data[] = {U32_LE(kWasmMagic ^ x), U32_LE(kWasmVersion)};
|
|
ModuleResult result = DecodeModuleNoHeader(base::ArrayVector(data));
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, WrongVersion) {
|
|
for (uint32_t x = 1; x; x <<= 1) {
|
|
const byte data[] = {U32_LE(kWasmMagic), U32_LE(kWasmVersion ^ x)};
|
|
ModuleResult result = DecodeModuleNoHeader(base::ArrayVector(data));
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, WrongSection) {
|
|
constexpr byte kInvalidSection = 0x1c;
|
|
const byte data[] = {kInvalidSection, 0};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DecodeEmpty) {
|
|
ModuleResult result = DecodeModule(base::VectorOf<uint8_t>(nullptr, 0));
|
|
EXPECT_TRUE(result.ok());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneGlobal) {
|
|
static const byte data[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kI32Code, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_I32V_1(13)) // init
|
|
};
|
|
|
|
{
|
|
// Should decode to exactly one global.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(1u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* global = &result.value()->globals.back();
|
|
|
|
EXPECT_EQ(kWasmI32, global->type);
|
|
EXPECT_EQ(0u, global->offset);
|
|
EXPECT_FALSE(global->mutability);
|
|
}
|
|
|
|
EXPECT_OFF_END_FAILURE(data, 1);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, S128Global) {
|
|
WASM_FEATURE_SCOPE(simd);
|
|
std::array<uint8_t, kSimd128Size> v = {1, 2, 3, 4, 5, 6, 7, 8,
|
|
9, 10, 11, 12, 13, 14, 15};
|
|
static const byte data[] = {SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kS128Code, // memory type
|
|
0, // immutable
|
|
WASM_SIMD_CONSTANT(v.data()), kExprEnd)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
if (!CheckHardwareSupportsSimd()) {
|
|
EXPECT_NOT_OK(result, "Wasm SIMD unsupported");
|
|
} else {
|
|
EXPECT_OK(result);
|
|
const WasmGlobal* global = &result.value()->globals.back();
|
|
EXPECT_EQ(kWasmS128, global->type);
|
|
EXPECT_EQ(0u, global->offset);
|
|
EXPECT_FALSE(global->mutability);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExternRefGlobal) {
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)),
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(2), // --
|
|
kExternRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_EXTERN_REF_NULL, // init
|
|
kFuncRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_REF_FUNC(1)), // init
|
|
SECTION(Element, // section name
|
|
ENTRY_COUNT(2), // entry count
|
|
DECLARATIVE, // flags 0
|
|
kExternalFunction, // type
|
|
ENTRY_COUNT(1), // func entry count
|
|
FUNC_INDEX(0), // func index
|
|
DECLARATIVE_WITH_ELEMENTS, // flags 1
|
|
kFuncRefCode, // local type
|
|
ENTRY_COUNT(1), // func ref count
|
|
REF_FUNC_ELEMENT(1)), // func ref
|
|
TWO_EMPTY_BODIES};
|
|
|
|
{
|
|
// Should decode to two globals.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->globals.size());
|
|
EXPECT_EQ(2u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* global = &result.value()->globals[0];
|
|
EXPECT_EQ(kWasmExternRef, global->type);
|
|
EXPECT_FALSE(global->mutability);
|
|
|
|
global = &result.value()->globals[1];
|
|
EXPECT_EQ(kWasmFuncRef, global->type);
|
|
EXPECT_FALSE(global->mutability);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FuncRefGlobal) {
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)),
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(2), // --
|
|
kFuncRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_FUNC_REF_NULL, // init
|
|
kFuncRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_REF_FUNC(1)), // init
|
|
SECTION(Element, // section name
|
|
ENTRY_COUNT(2), // entry count
|
|
DECLARATIVE, // flags 0
|
|
kExternalFunction, // type
|
|
ENTRY_COUNT(1), // func entry count
|
|
FUNC_INDEX(0), // func index
|
|
DECLARATIVE_WITH_ELEMENTS, // flags 1
|
|
kFuncRefCode, // local type
|
|
ENTRY_COUNT(1), // func ref count
|
|
REF_FUNC_ELEMENT(1)), // func ref
|
|
TWO_EMPTY_BODIES};
|
|
{
|
|
// Should decode to two globals.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->globals.size());
|
|
EXPECT_EQ(2u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* global = &result.value()->globals[0];
|
|
EXPECT_EQ(kWasmFuncRef, global->type);
|
|
EXPECT_FALSE(global->mutability);
|
|
|
|
global = &result.value()->globals[1];
|
|
EXPECT_EQ(kWasmFuncRef, global->type);
|
|
EXPECT_FALSE(global->mutability);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, InvalidFuncRefGlobal) {
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
TWO_EMPTY_FUNCTIONS(SIG_INDEX(0)),
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kFuncRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_REF_FUNC(7)), // invalid function index
|
|
TWO_EMPTY_BODIES};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExternRefGlobalWithGlobalInit) {
|
|
static const byte data[] = {
|
|
SECTION(Import, // --
|
|
ENTRY_COUNT(1), // number of imports
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // global name
|
|
kExternalGlobal, // import kind
|
|
kExternRefCode, // type
|
|
0), // mutability
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1),
|
|
kExternRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_GLOBAL(0)),
|
|
};
|
|
|
|
{
|
|
// Should decode to exactly one global.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* global = &result.value()->globals.back();
|
|
|
|
EXPECT_EQ(kWasmExternRef, global->type);
|
|
EXPECT_FALSE(global->mutability);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, NullGlobalWithGlobalInit) {
|
|
static const byte data[] = {
|
|
SECTION(Import, // --
|
|
ENTRY_COUNT(1), // number of imports
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('n'), // global name
|
|
kExternalGlobal, // import kind
|
|
kExternRefCode, // type
|
|
0), // mutability
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1),
|
|
kExternRefCode, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_GLOBAL(0)),
|
|
};
|
|
|
|
{
|
|
// Should decode to exactly one global.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
std::cout << result.error().message() << std::endl;
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* global = &result.value()->globals.back();
|
|
|
|
EXPECT_EQ(kWasmExternRef, global->type);
|
|
EXPECT_FALSE(global->mutability);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, GlobalInvalidType) {
|
|
static const byte data[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
64, // invalid value type
|
|
1, // mutable
|
|
WASM_INIT_EXPR_I32V_1(33)), // init
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, GlobalInvalidType2) {
|
|
static const byte data[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kVoidCode, // invalid value type
|
|
1, // mutable
|
|
WASM_INIT_EXPR_I32V_1(33)), // init
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, GlobalInitializer) {
|
|
static const byte no_initializer_no_end[] = {
|
|
SECTION(Global, //--
|
|
ENTRY_COUNT(1), //--
|
|
kI32Code, // type
|
|
1) // mutable
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(no_initializer_no_end, "Beyond end of code");
|
|
|
|
static const byte no_initializer[] = {
|
|
SECTION(Global, //--
|
|
ENTRY_COUNT(1), //--
|
|
kI32Code, // type
|
|
1, // mutable
|
|
kExprEnd) // --
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
no_initializer,
|
|
"expected 1 elements on the stack for constant expression, found 0");
|
|
|
|
static const byte too_many_initializers_no_end[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kI32Code, // type
|
|
1, // mutable
|
|
WASM_I32V_1(42), // one value is good
|
|
WASM_I32V_1(43)) // another value is too much
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(too_many_initializers_no_end,
|
|
"constant expression is missing 'end'");
|
|
|
|
static const byte too_many_initializers[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kI32Code, // type
|
|
1, // mutable
|
|
WASM_I32V_1(42), // one value is good
|
|
WASM_I32V_1(43), // another value is too much
|
|
kExprEnd)};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
too_many_initializers,
|
|
"expected 1 elements on the stack for constant expression, found 2");
|
|
|
|
static const byte missing_end_opcode[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kI32Code, // type
|
|
1, // mutable
|
|
WASM_I32V_1(42)) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(missing_end_opcode,
|
|
"constant expression is missing 'end'");
|
|
|
|
static const byte referencing_out_of_bounds_global[] = {
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kI32Code, // type
|
|
1, // mutable
|
|
WASM_GLOBAL_GET(42), kExprEnd) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(referencing_out_of_bounds_global,
|
|
"Invalid global index: 42");
|
|
|
|
static const byte referencing_undefined_global[] = {
|
|
SECTION(Global, ENTRY_COUNT(2), // --
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_GLOBAL_GET(1), kExprEnd, // init value
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_I32V(0), kExprEnd) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(referencing_undefined_global,
|
|
"Invalid global index: 1");
|
|
|
|
{
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte referencing_undefined_global_nested[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI32Code, true)),
|
|
SECTION(Global, ENTRY_COUNT(2), // --
|
|
kRefCode, 0, // type
|
|
0, // mutable
|
|
WASM_ARRAY_NEW_DEFAULT(0, // init value
|
|
WASM_GLOBAL_GET(1)), // --
|
|
kExprEnd, // --
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_I32V(10), kExprEnd) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(referencing_undefined_global_nested,
|
|
"Invalid global index: 1");
|
|
}
|
|
|
|
static const byte referencing_mutable_global[] = {
|
|
SECTION(Global, ENTRY_COUNT(2), // --
|
|
kI32Code, // type
|
|
1, // mutable
|
|
WASM_I32V(1), kExprEnd, // init value
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_GLOBAL_GET(0), kExprEnd) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
referencing_mutable_global,
|
|
"mutable globals cannot be used in constant expressions");
|
|
|
|
static const byte referencing_mutable_imported_global[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // --
|
|
ADD_COUNT('m'), ADD_COUNT('n'), // module, name
|
|
kExternalGlobal, // --
|
|
kI32Code, // type
|
|
1), // mutable
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_GLOBAL_GET(0), kExprEnd) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
referencing_mutable_imported_global,
|
|
"mutable globals cannot be used in constant expressions");
|
|
|
|
static const byte referencing_immutable_imported_global[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // --
|
|
ADD_COUNT('m'), ADD_COUNT('n'), // module, name
|
|
kExternalGlobal, // --
|
|
kI32Code, // type
|
|
0), // mutable
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_GLOBAL_GET(0), kExprEnd) // init value
|
|
};
|
|
EXPECT_VERIFIES(referencing_immutable_imported_global);
|
|
|
|
static const byte referencing_local_global[] = {
|
|
SECTION(Global, ENTRY_COUNT(2), // --
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_I32V(1), kExprEnd, // init value
|
|
kI32Code, // type
|
|
0, // mutable
|
|
WASM_GLOBAL_GET(0), kExprEnd) // init value
|
|
};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
referencing_local_global,
|
|
"non-imported globals cannot be used in constant expressions");
|
|
|
|
{
|
|
// But: experimental-wasm-gc should enable referencing immutable local
|
|
// globals.
|
|
WASM_FEATURE_SCOPE(gc);
|
|
EXPECT_VERIFIES(referencing_local_global);
|
|
// Referencing mutable glocals still invalid.
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
referencing_mutable_global,
|
|
"mutable globals cannot be used in constant expressions");
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
|
|
static const byte data[] = {SECTION(Global, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportMutableGlobal) {
|
|
{
|
|
static const byte data[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kI32Code, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_I32V_1(13)), // init
|
|
SECTION(Export, // --
|
|
ENTRY_COUNT(1), // export count
|
|
ADD_COUNT('n', 'a', 'm', 'e'), // name
|
|
kExternalGlobal, // global
|
|
0), // global index
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
{
|
|
static const byte data[] = {
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), // --
|
|
kI32Code, // local type
|
|
1, // mutable
|
|
WASM_INIT_EXPR_I32V_1(13)), // init
|
|
SECTION(Export, // --
|
|
ENTRY_COUNT(1), // export count
|
|
ADD_COUNT('n', 'a', 'm', 'e'), // name
|
|
kExternalGlobal, // global
|
|
0), // global index
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
}
|
|
|
|
static void AppendUint32v(std::vector<byte>* buffer, uint32_t val) {
|
|
while (true) {
|
|
uint32_t next = val >> 7;
|
|
uint32_t out = val & 0x7F;
|
|
if (next) {
|
|
buffer->push_back(static_cast<byte>(0x80 | out));
|
|
val = next;
|
|
} else {
|
|
buffer->push_back(static_cast<byte>(out));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, NGlobals) {
|
|
static const byte data[] = {
|
|
kF32Code, // memory type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_F32(7.7), // init
|
|
};
|
|
|
|
for (uint32_t i = 0; i < kV8MaxWasmGlobals; i = i * 13 + 1) {
|
|
std::vector<byte> buffer;
|
|
size_t size = SizeOfVarInt(i) + i * sizeof(data);
|
|
const byte globals[] = {kGlobalSectionCode, U32V_5(size)};
|
|
for (size_t g = 0; g != sizeof(globals); ++g) {
|
|
buffer.push_back(globals[g]);
|
|
}
|
|
AppendUint32v(&buffer, i); // Number of globals.
|
|
for (uint32_t j = 0; j < i; j++) {
|
|
buffer.insert(buffer.end(), data, data + sizeof(data));
|
|
}
|
|
|
|
ModuleResult result = DecodeModule(base::VectorOf(buffer));
|
|
EXPECT_OK(result);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TwoGlobals) {
|
|
static const byte data[] = {SECTION(Global, // --
|
|
ENTRY_COUNT(2), // --
|
|
kF32Code, // type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_F32(22.0), // --
|
|
kF64Code, // type
|
|
1, // mutable
|
|
WASM_INIT_EXPR_F64(23.0))}; // --
|
|
|
|
{
|
|
// Should decode to exactly two globals.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* g0 = &result.value()->globals[0];
|
|
|
|
EXPECT_EQ(kWasmF32, g0->type);
|
|
EXPECT_EQ(0u, g0->offset);
|
|
EXPECT_FALSE(g0->mutability);
|
|
|
|
const WasmGlobal* g1 = &result.value()->globals[1];
|
|
|
|
EXPECT_EQ(kWasmF64, g1->type);
|
|
EXPECT_EQ(8u, g1->offset);
|
|
EXPECT_TRUE(g1->mutability);
|
|
}
|
|
|
|
EXPECT_OFF_END_FAILURE(data, 1);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, RefNullGlobal) {
|
|
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1), kFuncRefCode, 1,
|
|
WASM_REF_NULL(kFuncRefCode), kExprEnd)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, RefNullGlobalInvalid1) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1), kRefNullCode, 0,
|
|
1, WASM_REF_NULL(0), kExprEnd)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "Type index 0 is out of bounds");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, RefNullGlobalInvalid2) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1), kFuncRefCode, 1,
|
|
kExprRefNull, U32V_5(1000001), kExprEnd)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result,
|
|
"Type index 1000001 is greater than the maximum number 1000000 "
|
|
"of type definitions supported by V8");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, StructNewInitExpr) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
|
|
static const byte basic[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true))),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_STRUCT_NEW(0, WASM_I32V(42)))};
|
|
EXPECT_VERIFIES(basic);
|
|
|
|
static const byte global_args[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true))),
|
|
SECTION(Global, ENTRY_COUNT(2), // --
|
|
kI32Code, 0, // type, mutability
|
|
WASM_INIT_EXPR_I32V_1(10), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_STRUCT_NEW(0, WASM_GLOBAL_GET(0)))};
|
|
EXPECT_VERIFIES(global_args);
|
|
|
|
static const byte type_error[] = {
|
|
SECTION(Type, ENTRY_COUNT(2), // --
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI64Code, true))),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 1, 0, // type, mutability
|
|
WASM_INIT_EXPR_STRUCT_NEW(0, WASM_I32V(42)))};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
type_error,
|
|
"type error in constant expression[0] (expected (ref 1), got (ref 0))");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ArrayNewFixedInitExpr) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
|
|
static const byte basic[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI16Code, true)),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_ARRAY_NEW_FIXED(0, 3, WASM_I32V(10), WASM_I32V(20),
|
|
WASM_I32V(30)))};
|
|
EXPECT_VERIFIES(basic);
|
|
|
|
static const byte basic_static[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI16Code, true)),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_ARRAY_NEW_FIXED(0, 3, WASM_I32V(10), WASM_I32V(20),
|
|
WASM_I32V(30)))};
|
|
EXPECT_VERIFIES(basic_static);
|
|
|
|
static const byte basic_immutable[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI32Code, false)),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_ARRAY_NEW_FIXED(0, 3, WASM_I32V(10), WASM_I32V(20),
|
|
WASM_I32V(30)))};
|
|
EXPECT_VERIFIES(basic_immutable);
|
|
|
|
static const byte type_error[] = {
|
|
SECTION(Type, ENTRY_COUNT(2), // --
|
|
WASM_ARRAY_DEF(kI32Code, true),
|
|
WASM_ARRAY_DEF(WASM_SEQ(kRefCode, 0), true)),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 1, 0, // type, mutability
|
|
WASM_INIT_EXPR_ARRAY_NEW_FIXED(0, 1, WASM_I32V(42)))};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
type_error,
|
|
"type error in constant expression[0] (expected (ref 1), got (ref 0))");
|
|
|
|
static const byte subexpr_type_error[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI64Code, true)),
|
|
SECTION(
|
|
Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_ARRAY_NEW_FIXED(0, 2, WASM_I64V(42), WASM_I32V(142)))};
|
|
EXPECT_FAILURE_WITH_MSG(subexpr_type_error,
|
|
"array.new_fixed[1] expected type i64, found "
|
|
"i32.const of type i32");
|
|
|
|
static const byte length_error[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI16Code, true)),
|
|
SECTION(Global, ENTRY_COUNT(1), // --
|
|
kRefCode, 0, 0, // type, mutability
|
|
WASM_INIT_EXPR_ARRAY_NEW_FIXED(0, 10, WASM_I32V(10),
|
|
WASM_I32V(20), WASM_I32V(30)))};
|
|
EXPECT_FAILURE_WITH_MSG(length_error,
|
|
"not enough arguments on the stack for "
|
|
"array.new_fixed (need 11, got 4)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, EmptyStruct) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte empty_struct[] = {SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(0))}; // field count
|
|
|
|
EXPECT_VERIFIES(empty_struct);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, InvalidStructTypeDef) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte all_good[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(1), // field count
|
|
kI32Code, // perfectly valid field type
|
|
1)}; // mutability
|
|
EXPECT_VERIFIES(all_good);
|
|
|
|
static const byte invalid_field_type[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(1), // field count
|
|
kWasmArrayTypeCode, // bogus field type
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(invalid_field_type, "invalid value type");
|
|
|
|
static const byte field_type_oob_ref[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(1), // field count
|
|
kRefNullCode, // field type: reference...
|
|
3, // ...to nonexistent type
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(field_type_oob_ref, "Type index 3 is out of bounds");
|
|
|
|
static const byte field_type_invalid_ref[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(1), // field count
|
|
kRefNullCode, // field type: reference...
|
|
U32V_4(1234567), // ...to a type > kV8MaxWasmTypes
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(field_type_invalid_ref, "greater than the maximum");
|
|
|
|
static const byte field_type_invalid_ref2[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(1), // field count
|
|
kRefNullCode, // field type: reference...
|
|
kI32Code, // ...to a non-referenceable type
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(field_type_invalid_ref2, "Unknown heap type");
|
|
|
|
static const byte not_enough_field_types[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(2), // field count
|
|
kI32Code, // field type 1
|
|
1)}; // mutability 1
|
|
EXPECT_FAILURE_WITH_MSG(not_enough_field_types, "expected 1 byte");
|
|
|
|
static const byte not_enough_field_types2[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(2), // field count
|
|
kI32Code, // field type 1
|
|
1, // mutability 1
|
|
kI32Code)}; // field type 2
|
|
EXPECT_FAILURE_WITH_MSG(not_enough_field_types2, "expected 1 byte");
|
|
|
|
static const byte invalid_mutability[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmStructTypeCode, // --
|
|
U32V_1(1), // field count
|
|
kI32Code, // field type
|
|
2)}; // invalid mutability value
|
|
EXPECT_FAILURE_WITH_MSG(invalid_mutability, "invalid mutability");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, InvalidArrayTypeDef) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte all_good[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kI32Code, // perfectly valid field type
|
|
1)}; // mutability
|
|
EXPECT_VERIFIES(all_good);
|
|
|
|
static const byte invalid_field_type[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kWasmArrayTypeCode, // bogus field type
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(invalid_field_type, "invalid value type");
|
|
|
|
static const byte field_type_oob_ref[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kRefNullCode, // field type: reference...
|
|
3, // ...to nonexistent type
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(field_type_oob_ref, "Type index 3 is out of bounds");
|
|
|
|
static const byte field_type_invalid_ref[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kRefNullCode, // field type: reference...
|
|
U32V_3(1234567), // ...to a type > kV8MaxWasmTypes
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(field_type_invalid_ref, "Unknown heap type");
|
|
|
|
static const byte field_type_invalid_ref2[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kRefNullCode, // field type: reference...
|
|
kI32Code, // ...to a non-referenceable type
|
|
1)}; // mutability
|
|
EXPECT_FAILURE_WITH_MSG(field_type_invalid_ref2, "Unknown heap type");
|
|
|
|
static const byte invalid_mutability[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kI32Code, // field type
|
|
2)}; // invalid mutability value
|
|
EXPECT_FAILURE_WITH_MSG(invalid_mutability, "invalid mutability");
|
|
|
|
static const byte immutable[] = {SECTION(Type,
|
|
ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, // --
|
|
kI32Code, // field type
|
|
0)}; // immmutability
|
|
EXPECT_VERIFIES(immutable);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TypeCanonicalization) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte identical_group[] = {
|
|
SECTION(Type, // --
|
|
ENTRY_COUNT(2), // two identical rec. groups
|
|
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, kI32Code, 0, // --
|
|
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, kI32Code, 0),
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), kRefCode, 0, 0, // Type, mutability
|
|
WASM_ARRAY_NEW_FIXED(1, 1, WASM_I32V(10)),
|
|
kExprEnd) // initial value
|
|
};
|
|
|
|
// Global initializer should verify as identical type in other group
|
|
EXPECT_VERIFIES(identical_group);
|
|
|
|
static const byte non_identical_group[] = {
|
|
SECTION(Type, // --
|
|
ENTRY_COUNT(2), // two distrinct rec. groups
|
|
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(1), // --
|
|
kWasmArrayTypeCode, kI32Code, 0, // --
|
|
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(2), // --
|
|
kWasmArrayTypeCode, kI32Code, 0, // --
|
|
kWasmStructTypeCode, ENTRY_COUNT(0)),
|
|
SECTION(Global, // --
|
|
ENTRY_COUNT(1), kRefCode, 0, 0, // Type, mutability
|
|
WASM_ARRAY_NEW_FIXED(1, 1, WASM_I32V(10)),
|
|
kExprEnd) // initial value
|
|
};
|
|
|
|
// Global initializer should not verify as type in distinct rec. group.
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
non_identical_group,
|
|
"type error in constant expression[0] (expected (ref 0), got (ref 1))");
|
|
}
|
|
|
|
// Tests that all types in a rec. group are checked for supertype validity.
|
|
TEST_F(WasmModuleVerifyTest, InvalidSupertypeInRecGroup) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte invalid_supertype[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(2), // --
|
|
kWasmArrayTypeCode, kI32Code, 0, // --
|
|
kWasmSubtypeCode, 1, 0, // supertype count, supertype
|
|
kWasmArrayTypeCode, kI64Code, 0)};
|
|
|
|
EXPECT_FAILURE_WITH_MSG(invalid_supertype,
|
|
"type 1 has invalid explicit supertype 0");
|
|
}
|
|
|
|
// Tests supertype declaration with 0 supertypes.
|
|
TEST_F(WasmModuleVerifyTest, SuperTypeDeclarationWith0Supertypes) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte zero_supertypes[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), // --
|
|
kWasmSubtypeCode, 0, // supertype count
|
|
kWasmArrayTypeCode, kI32Code, 0)};
|
|
|
|
EXPECT_VERIFIES(zero_supertypes);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
|
|
static const byte data[] = {SECTION(Tag, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(0u, result.value()->tags.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneI32Exception) {
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_x(kI32Code)), // sig#0 (i32)
|
|
SECTION(Tag, ENTRY_COUNT(1),
|
|
EXCEPTION_ENTRY(SIG_INDEX(0)))}; // except[0] (sig#0)
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(1u, result.value()->tags.size());
|
|
|
|
const WasmTag& e0 = result.value()->tags.front();
|
|
EXPECT_EQ(1u, e0.sig->parameter_count());
|
|
EXPECT_EQ(kWasmI32, e0.sig->GetParam(0));
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TwoExceptions) {
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(2),
|
|
SIG_ENTRY_v_x(kI32Code), // sig#0 (i32)
|
|
SIG_ENTRY_v_xx(kF32Code, kI64Code)), // sig#1 (f32, i64)
|
|
SECTION(Tag, ENTRY_COUNT(2),
|
|
EXCEPTION_ENTRY(SIG_INDEX(1)), // except[0] (sig#1)
|
|
EXCEPTION_ENTRY(SIG_INDEX(0)))}; // except[1] (sig#0)
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->tags.size());
|
|
const WasmTag& e0 = result.value()->tags.front();
|
|
EXPECT_EQ(2u, e0.sig->parameter_count());
|
|
EXPECT_EQ(kWasmF32, e0.sig->GetParam(0));
|
|
EXPECT_EQ(kWasmI64, e0.sig->GetParam(1));
|
|
const WasmTag& e1 = result.value()->tags.back();
|
|
EXPECT_EQ(kWasmI32, e1.sig->GetParam(0));
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_index) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
SECTION(Tag, ENTRY_COUNT(1),
|
|
EXCEPTION_ENTRY(
|
|
SIG_INDEX(23)))}; // except[0] (sig#23 [out-of-bounds])
|
|
// Should fail decoding exception section.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "signature index 23 out of bounds");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_return) {
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_i_i),
|
|
SECTION(Tag, ENTRY_COUNT(1),
|
|
EXCEPTION_ENTRY(
|
|
SIG_INDEX(0)))}; // except[0] (sig#0 [invalid-return-type])
|
|
// Should fail decoding exception section.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "tag signature 0 has non-void return");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Exception_invalid_attribute) {
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_i_i),
|
|
SECTION(Tag, ENTRY_COUNT(1), 23,
|
|
SIG_INDEX(0))}; // except[0] (sig#0) [invalid-attribute]
|
|
// Should fail decoding exception section.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "exception attribute 23 not supported");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TagSectionCorrectPlacement) {
|
|
static const byte data[] = {SECTION(Memory, ENTRY_COUNT(0)),
|
|
SECTION(Tag, ENTRY_COUNT(0)),
|
|
SECTION(Global, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TagSectionAfterGlobal) {
|
|
static const byte data[] = {SECTION(Global, ENTRY_COUNT(0)),
|
|
SECTION(Tag, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result,
|
|
"The Tag section must appear before the Global section");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TagSectionBeforeMemory) {
|
|
static const byte data[] = {SECTION(Tag, ENTRY_COUNT(0)),
|
|
SECTION(Memory, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "unexpected section <Memory>");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TagSectionAfterTableBeforeMemory) {
|
|
static_assert(kMemorySectionCode + 1 == kGlobalSectionCode);
|
|
static const byte data[] = {SECTION(Table, ENTRY_COUNT(0)),
|
|
SECTION(Tag, ENTRY_COUNT(0)),
|
|
SECTION(Memory, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "unexpected section <Memory>");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TagImport) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
SECTION(Import, // section header
|
|
ENTRY_COUNT(1), // number of imports
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('e', 'x'), // tag name
|
|
kExternalTag, // import kind
|
|
EXCEPTION_ENTRY(SIG_INDEX(0)))}; // except[0] (sig#0)
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(1u, result.value()->tags.size());
|
|
EXPECT_EQ(1u, result.value()->import_table.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExceptionExport) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
SECTION(Tag, ENTRY_COUNT(1),
|
|
EXCEPTION_ENTRY(SIG_INDEX(0))), // except[0] (sig#0)
|
|
SECTION(Export, ENTRY_COUNT(1), // --
|
|
NO_NAME, // --
|
|
kExternalTag, // --
|
|
EXCEPTION_INDEX(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(1u, result.value()->tags.size());
|
|
EXPECT_EQ(1u, result.value()->export_table.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneSignature) {
|
|
{
|
|
static const byte data[] = {TYPE_SECTION_ONE_SIG_VOID_VOID};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
{
|
|
static const byte data[] = {SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_i_i)};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleSignatures) {
|
|
static const byte data[] = {
|
|
SECTION(Type, // --
|
|
ENTRY_COUNT(3), // --
|
|
SIG_ENTRY_v_v, // void -> void
|
|
SIG_ENTRY_x_x(kI32Code, kF32Code), // f32 -> i32
|
|
SIG_ENTRY_x_xx(kI32Code, kF64Code, kF64Code)), // f64,f64 -> i32
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(3u, result.value()->types.size());
|
|
if (result.value()->types.size() == 3) {
|
|
EXPECT_EQ(0u, result.value()->signature(0)->return_count());
|
|
EXPECT_EQ(1u, result.value()->signature(1)->return_count());
|
|
EXPECT_EQ(1u, result.value()->signature(2)->return_count());
|
|
|
|
EXPECT_EQ(0u, result.value()->signature(0)->parameter_count());
|
|
EXPECT_EQ(1u, result.value()->signature(1)->parameter_count());
|
|
EXPECT_EQ(2u, result.value()->signature(2)->parameter_count());
|
|
}
|
|
|
|
EXPECT_OFF_END_FAILURE(data, 1);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, CanonicalTypeIds) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Type, // --
|
|
ENTRY_COUNT(5), // --
|
|
WASM_STRUCT_DEF( // Struct definition
|
|
FIELD_COUNT(1), // --
|
|
STRUCT_FIELD(kI32Code, true)), // --
|
|
SIG_ENTRY_x_x(kI32Code, kF32Code), // f32 -> i32
|
|
SIG_ENTRY_x_x(kI32Code, kF64Code), // f64 -> i32
|
|
SIG_ENTRY_x_x(kI32Code, kF32Code), // f32 -> i32 (again)
|
|
WASM_ARRAY_DEF(kI32Code, true)) // Array definition
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
const WasmModule* module = result.value().get();
|
|
|
|
EXPECT_EQ(5u, module->types.size());
|
|
EXPECT_EQ(5u, module->isorecursive_canonical_type_ids.size());
|
|
|
|
EXPECT_EQ(0u, module->isorecursive_canonical_type_ids[0]);
|
|
EXPECT_EQ(1u, module->isorecursive_canonical_type_ids[1]);
|
|
EXPECT_EQ(2u, module->isorecursive_canonical_type_ids[2]);
|
|
EXPECT_EQ(1u, module->isorecursive_canonical_type_ids[3]);
|
|
EXPECT_EQ(3u, module->isorecursive_canonical_type_ids[4]);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableImportedGlobal) {
|
|
// Import 2 globals so that we can initialize data with a global index != 0.
|
|
const byte data[] = {
|
|
SECTION(Import, // section header
|
|
ENTRY_COUNT(2), // number of imports
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // global name
|
|
kExternalGlobal, // import kind
|
|
kI32Code, // type
|
|
0, // mutability
|
|
ADD_COUNT('n'), // module name
|
|
ADD_COUNT('g'), // global name
|
|
kExternalGlobal, // import kind
|
|
kI32Code, // type
|
|
0), // mutability
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_GLOBAL(1), // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataSegmentWithMutableImportedGlobal) {
|
|
// Only an immutable imported global can be used as an init_expr.
|
|
const byte data[] = {
|
|
SECTION(Import, // section header
|
|
ENTRY_COUNT(1), // number of imports
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // global name
|
|
kExternalGlobal, // import kind
|
|
kI32Code, // type
|
|
1), // mutability
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_GLOBAL(0), // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableGlobal) {
|
|
// Only an immutable imported global can be used as an init_expr.
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Global, ENTRY_COUNT(1),
|
|
kI32Code, // local type
|
|
0, // immutable
|
|
WASM_INIT_EXPR_I32V_3(0x9BBAA)), // init
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_GLOBAL(0), // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneDataSegment) {
|
|
const byte kDataSegmentSourceOffset = 24;
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_I32V_3(0x9BBAA), // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
|
|
{
|
|
EXPECT_VERIFIES(data);
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(0u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(1u, result.value()->data_segments.size());
|
|
|
|
const WasmDataSegment* segment = &result.value()->data_segments.back();
|
|
|
|
EXPECT_EQ(kDataSegmentSourceOffset, segment->source.offset());
|
|
EXPECT_EQ(3u, segment->source.length());
|
|
}
|
|
|
|
EXPECT_OFF_END_FAILURE(data, 14);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TwoDataSegments) {
|
|
const byte kDataSegment0SourceOffset = 24;
|
|
const byte kDataSegment1SourceOffset = kDataSegment0SourceOffset + 11;
|
|
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Data,
|
|
ENTRY_COUNT(2), // segment count
|
|
LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_I32V_3(0x7FFEE), // #0: dest addr
|
|
U32V_1(4), // source size
|
|
1, 2, 3, 4, // data bytes
|
|
LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_I32V_3(0x6DDCC), // #1: dest addr
|
|
U32V_1(10), // source size
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // data bytes
|
|
};
|
|
|
|
{
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(0u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(2u, result.value()->data_segments.size());
|
|
|
|
const WasmDataSegment* s0 = &result.value()->data_segments[0];
|
|
const WasmDataSegment* s1 = &result.value()->data_segments[1];
|
|
|
|
EXPECT_EQ(kDataSegment0SourceOffset, s0->source.offset());
|
|
EXPECT_EQ(4u, s0->source.length());
|
|
|
|
EXPECT_EQ(kDataSegment1SourceOffset, s1->source.offset());
|
|
EXPECT_EQ(10u, s1->source.length());
|
|
}
|
|
|
|
EXPECT_OFF_END_FAILURE(data, 14);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataWithoutMemory) {
|
|
const byte data[] = {
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_I32V_3(0x9BBAA), // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MaxMaximumMemorySize) {
|
|
{
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 0, U32V_3(65536))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
{
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 0, U32V_3(65537))};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, InvalidMemoryLimits) {
|
|
{
|
|
const byte kInvalidLimits = 0x15;
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kInvalidLimits, 0, 10)};
|
|
EXPECT_FAILURE_WITH_MSG(data, "invalid memory limits flags 0x15");
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataSegment_wrong_init_type) {
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0,
|
|
WASM_INIT_EXPR_F64(9.9), // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataSegmentEndOverflow) {
|
|
const byte data[] = {
|
|
SECTION(Memory, // memory section
|
|
ENTRY_COUNT(1), kWithMaximum, 28, 28),
|
|
SECTION(Data, // data section
|
|
ENTRY_COUNT(1), // one entry
|
|
LINEAR_MEMORY_INDEX_0, // mem index
|
|
WASM_INIT_EXPR_I32V_1(0), // offset
|
|
U32V_5(0xFFFFFFFF)) // size
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
if (result.ok()) {
|
|
EXPECT_EQ(1u, result.value()->types.size());
|
|
EXPECT_EQ(1u, result.value()->functions.size());
|
|
EXPECT_EQ(1u, result.value()->tables.size());
|
|
EXPECT_EQ(1u, result.value()->tables[0].initial_size);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionWithInternalTable) {
|
|
static const byte data[] = {
|
|
// table ---------------------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element, ENTRY_COUNT(0))};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionWithImportedTable) {
|
|
static const byte data[] = {
|
|
// imports -------------------------------------------------------------
|
|
SECTION(Import, ENTRY_COUNT(1),
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('t'), // table name
|
|
kExternalTable, // import kind
|
|
kFuncRefCode, // elem_type
|
|
0, // no maximum field
|
|
1), // initial size
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element, ENTRY_COUNT(0))};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionWithoutTable) {
|
|
// Test that an element section without a table causes a validation error.
|
|
static const byte data[] = {
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(1), // entry count
|
|
0, // table index
|
|
0, // offset
|
|
0) // number of elements
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Regression_735887) {
|
|
// Test with an invalid function index in the element section.
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(1), // entry count
|
|
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
|
|
1, // elements count
|
|
0x9A) // invalid I32V as function index
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneIndirectFunction_one_entry) {
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(1), // entry count
|
|
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
|
|
1, // elements count
|
|
FUNC_INDEX(0)),
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(1u, result.value()->types.size());
|
|
EXPECT_EQ(1u, result.value()->functions.size());
|
|
EXPECT_EQ(1u, result.value()->tables.size());
|
|
EXPECT_EQ(1u, result.value()->tables[0].initial_size);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
SECTION(Type,
|
|
ENTRY_COUNT(2), // --
|
|
SIG_ENTRY_v_v, // void -> void
|
|
SIG_ENTRY_v_x(kI32Code)), // void -> i32
|
|
// funcs ------------------------------------------------------
|
|
FOUR_EMPTY_FUNCTIONS(SIG_INDEX(0)),
|
|
// table declaration -------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 8),
|
|
// table elements ----------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(1), // entry count
|
|
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
|
|
ADD_COUNT(FUNC_INDEX(0), FUNC_INDEX(1), FUNC_INDEX(2),
|
|
FUNC_INDEX(3), FUNC_INDEX(0), FUNC_INDEX(1),
|
|
FUNC_INDEX(2), FUNC_INDEX(3))),
|
|
FOUR_EMPTY_BODIES};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(2u, result.value()->types.size());
|
|
EXPECT_EQ(4u, result.value()->functions.size());
|
|
EXPECT_EQ(1u, result.value()->tables.size());
|
|
EXPECT_EQ(8u, result.value()->tables[0].initial_size);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
|
|
// Test that if we have multiple tables, in the element section we can target
|
|
// and initialize all tables.
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(2), // section header
|
|
kFuncRefCode, 0, 5, // table 0
|
|
kFuncRefCode, 0, 9), // table 1
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(2), // entry count
|
|
TABLE_INDEX0, // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(0), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(1), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(7), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0)), // entry 1
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
|
|
// Test that if we have multiple tables, both imported and module-defined, in
|
|
// the element section we can target and initialize all tables.
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// imports -------------------------------------------------------------
|
|
SECTION(Import, ENTRY_COUNT(2),
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('t'), // table name
|
|
kExternalTable, // import kind
|
|
kFuncRefCode, // elem_type
|
|
0, // no maximum field
|
|
5, // initial size
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('s'), // table name
|
|
kExternalTable, // import kind
|
|
kFuncRefCode, // elem_type
|
|
0, // no maximum field
|
|
10), // initial size
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(2), // section header
|
|
kFuncRefCode, 0, 15, // table 0
|
|
kFuncRefCode, 0, 19), // table 1
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
4, // entry count
|
|
TABLE_INDEX0, // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(0), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(1), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(7), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0), // entry 1
|
|
TABLE_INDEX(2), // element for table 2
|
|
WASM_INIT_EXPR_I32V_1(12), // index
|
|
kExternalFunction, // type
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(3), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(17), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0)), // entry 1
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
|
// Test that the order in which tables are targeted in the element secion
|
|
// can be arbitrary.
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(2), // section header
|
|
kFuncRefCode, 0, 5, // table 0
|
|
kFuncRefCode, 0, 9), // table 1
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(3), // entry count
|
|
TABLE_INDEX0, // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(0), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(1), // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(7), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0), // entry 1
|
|
TABLE_INDEX0, // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(3), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0)), // function
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
|
// Test that the order in which tables are targeted in the element secion can
|
|
// be arbitrary. In this test, tables can be both imported and module-defined.
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// imports -------------------------------------------------------------
|
|
SECTION(Import, ENTRY_COUNT(2),
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('t'), // table name
|
|
kExternalTable, // import kind
|
|
kFuncRefCode, // elem_type
|
|
0, // no maximum field
|
|
5, // initial size
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('s'), // table name
|
|
kExternalTable, // import kind
|
|
kFuncRefCode, // elem_type
|
|
0, // no maximum field
|
|
10), // initial size
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(2), // section header
|
|
kFuncRefCode, 0, 15, // table 0
|
|
kFuncRefCode, 0, 19), // table 1
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
4, // entry count
|
|
TABLE_INDEX(2), // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(10), // index
|
|
kExternalFunction, // type
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(3), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(17), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0), // entry 1
|
|
TABLE_INDEX0, // element for table 2
|
|
WASM_INIT_EXPR_I32V_1(2), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(1), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(7), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0)), // entry 1
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionInitExternRefTableWithFuncRef) {
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(2), // section header
|
|
kExternRefCode, 0, 5, // table 0
|
|
kFuncRefCode, 0, 9), // table 1
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(2), // entry count
|
|
TABLE_INDEX0, // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(0), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(1), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(7), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0)), // entry 1
|
|
// code ----------------------------------------------------------------
|
|
ONE_EMPTY_BODY,
|
|
};
|
|
|
|
EXPECT_FAILURE_WITH_MSG(data,
|
|
"An active element segment with function indices as "
|
|
"elements must reference a table of type funcref. "
|
|
"Instead, table 0 of type externref is referenced.");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionInitFuncRefTableWithFuncRefNull) {
|
|
static const byte data[] = {
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), // section header
|
|
kFuncRefCode, 0, 9), // table 0
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(1), // entry count
|
|
ACTIVE_WITH_ELEMENTS, TABLE_INDEX0, // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(0), // index
|
|
kFuncRefCode, // .
|
|
1, // elements count
|
|
WASM_INIT_EXPR_FUNC_REF_NULL) // function
|
|
};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionInitFuncRefTableWithExternRefNull) {
|
|
static const byte data[] = {
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), // section header
|
|
kFuncRefCode, 0, 9), // table 0
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(1), // entry count
|
|
ACTIVE_WITH_ELEMENTS, TABLE_INDEX0, // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(0), // index
|
|
kFuncRefCode, // .
|
|
1, // elements count
|
|
WASM_INIT_EXPR_EXTERN_REF_NULL) // function
|
|
};
|
|
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
data,
|
|
"type error in constant expression[0] (expected funcref, got externref)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitExternRefImportedTable) {
|
|
// Test that imported tables of type ExternRef cannot be initialized in the
|
|
// elements section.
|
|
static const byte data[] = {
|
|
// sig#0 ---------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// imports -------------------------------------------------------------
|
|
SECTION(Import, ENTRY_COUNT(2),
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('t'), // table name
|
|
kExternalTable, // import kind
|
|
kFuncRefCode, // elem_type
|
|
0, // no maximum field
|
|
5, // initial size
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('s'), // table name
|
|
kExternalTable, // import kind
|
|
kExternRefCode, // elem_type
|
|
0, // no maximum field
|
|
10), // initial size
|
|
// funcs ---------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration ---------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(2), // section header
|
|
kFuncRefCode, 0, 15, // table 0
|
|
kFuncRefCode, 0, 19), // table 1
|
|
// elements ------------------------------------------------------------
|
|
SECTION(Element,
|
|
ENTRY_COUNT(4), // entry count
|
|
TABLE_INDEX0, // element for table 0
|
|
WASM_INIT_EXPR_I32V_1(10), // index
|
|
1, // elements count
|
|
FUNC_INDEX(0), // function
|
|
TABLE_INDEX(1), // element for table 1
|
|
WASM_INIT_EXPR_I32V_1(17), // index
|
|
kExternalFunction, // type
|
|
2, // elements count
|
|
FUNC_INDEX(0), // entry 0
|
|
FUNC_INDEX(0)), // entry 1
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ElementSectionGlobalGetOutOfBounds) {
|
|
static const byte data[] = {
|
|
SECTION(Element, ENTRY_COUNT(1),
|
|
0x05, // Mode: Passive with expressions-as-elements
|
|
kFuncRefCode, // type
|
|
ENTRY_COUNT(1), // element count
|
|
kExprGlobalGet, 0x00, kExprEnd)}; // initial value
|
|
EXPECT_FAILURE_WITH_MSG(data, "Invalid global index: 0");
|
|
}
|
|
|
|
// Make sure extended constants do not work without the experimental feature.
|
|
TEST_F(WasmModuleVerifyTest, ExtendedConstantsFail) {
|
|
static const byte data[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // one import
|
|
0x01, 'm', 0x01, 'g', // module, name
|
|
kExternalGlobal, kI32Code, 0), // type, mutability
|
|
SECTION(Global, ENTRY_COUNT(1), // one defined global
|
|
kI32Code, 0, // type, mutability
|
|
// initializer
|
|
kExprGlobalGet, 0x00, kExprGlobalGet, 0x00, kExprI32Add,
|
|
kExprEnd)};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
data, "opcode i32.add is not allowed in constant expressions");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExtendedConstantsI32) {
|
|
WASM_FEATURE_SCOPE(extended_const);
|
|
static const byte data[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // one import
|
|
0x01, 'm', 0x01, 'g', // module, name
|
|
kExternalGlobal, kI32Code, 0), // type, mutability
|
|
SECTION(Global, ENTRY_COUNT(1), // one defined global
|
|
kI32Code, 0, // type, mutability
|
|
// initializer
|
|
kExprGlobalGet, 0x00, kExprGlobalGet, 0x00, kExprI32Add,
|
|
kExprGlobalGet, 0x00, kExprI32Sub, kExprGlobalGet, 0x00,
|
|
kExprI32Mul, kExprEnd)};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExtendedConstantsI64) {
|
|
WASM_FEATURE_SCOPE(extended_const);
|
|
static const byte data[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // one import
|
|
0x01, 'm', 0x01, 'g', // module, name
|
|
kExternalGlobal, kI64Code, 0), // type, mutability
|
|
SECTION(Global, ENTRY_COUNT(1), // one defined global
|
|
kI64Code, 0, // type, mutability
|
|
// initializer
|
|
kExprGlobalGet, 0x00, kExprGlobalGet, 0x00, kExprI64Add,
|
|
kExprGlobalGet, 0x00, kExprI64Sub, kExprGlobalGet, 0x00,
|
|
kExprI64Mul, kExprEnd)};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExtendedConstantsTypeError) {
|
|
WASM_FEATURE_SCOPE(extended_const);
|
|
static const byte data[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // one import
|
|
0x01, 'm', 0x01, 'g', // module, name
|
|
kExternalGlobal, kI32Code, 0), // type, mutability
|
|
SECTION(Global, ENTRY_COUNT(1), // one defined global
|
|
kI32Code, 0, // type, mutability
|
|
// initializer
|
|
kExprGlobalGet, 0x00, kExprI64Const, 1, kExprI32Add, kExprEnd)};
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
data, "i32.add[1] expected type i32, found i64.const of type i64");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, IndirectFunctionNoFunctions) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// indirect table ----------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), 1, 0, 0)};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, IndirectFunctionInvalidIndex) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// functions ---------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// indirect table ----------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), 1, 1, 0)};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleTables) {
|
|
static const byte data[] = {
|
|
SECTION(Table, // table section
|
|
ENTRY_COUNT(2), // 2 tables
|
|
kFuncRefCode, // table 1: type
|
|
0, // table 1: no maximum
|
|
10, // table 1: minimum size
|
|
kExternRefCode, // table 2: type
|
|
0, // table 2: no maximum
|
|
11), // table 2: minimum size
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(2u, result.value()->tables.size());
|
|
|
|
EXPECT_EQ(10u, result.value()->tables[0].initial_size);
|
|
EXPECT_EQ(kWasmFuncRef, result.value()->tables[0].type);
|
|
|
|
EXPECT_EQ(11u, result.value()->tables[1].initial_size);
|
|
EXPECT_EQ(kWasmExternRef, result.value()->tables[1].type);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TypedFunctionTable) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_x(kI32Code)),
|
|
SECTION(Table, // table section
|
|
ENTRY_COUNT(1), // 1 table
|
|
kRefNullCode, 0, // table 0: type
|
|
0, 10)}; // table 0: limits
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(ValueType::RefNull(0), result.value()->tables[0].type);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, NullableTableIllegalInitializer) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_v), // type section
|
|
ONE_EMPTY_FUNCTION(0), // function section
|
|
SECTION(Table, // table section
|
|
ENTRY_COUNT(1), // 1 table
|
|
kRefNullCode, 0, // table 0: type
|
|
0, 10, // table 0: limits
|
|
kExprRefFunc, 0, kExprEnd)}; // table 0: initializer
|
|
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
data,
|
|
"section was shorter than expected size (8 bytes expected, 5 decoded)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, IllegalTableTypes) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
|
|
using Vec = std::vector<byte>;
|
|
|
|
static Vec table_types[] = {{kI32Code}, {kF64Code}};
|
|
|
|
for (Vec type : table_types) {
|
|
Vec data = {
|
|
SECTION(Type, ENTRY_COUNT(2),
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
|
WASM_ARRAY_DEF(kI32Code, true)),
|
|
kTableSectionCode, static_cast<byte>(type.size() + 3), byte{1}};
|
|
// Last elements are section size and entry count
|
|
|
|
// Add table type
|
|
data.insert(data.end(), type.begin(), type.end());
|
|
// Add table limits
|
|
data.insert(data.end(), {byte{0}, byte{10}});
|
|
|
|
auto result = DecodeModule(base::VectorOf(data));
|
|
EXPECT_NOT_OK(result, "Only reference types can be used as table types");
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TableWithInitializer) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_v), // type section
|
|
ONE_EMPTY_FUNCTION(0), // function section
|
|
SECTION(Table, // table section
|
|
ENTRY_COUNT(1), // 1 table
|
|
0x40, // table 0: has initializer
|
|
kRefNullCode, 0, // table 0: type
|
|
0, 10, // table 0: limits
|
|
kExprRefFunc, 0, kExprEnd), // table 0: initial value
|
|
SECTION(Code, ENTRY_COUNT(1), NOP_BODY)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(ValueType::RefNull(0), result.value()->tables[0].type);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, NonNullableTable) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_v), // type section
|
|
ONE_EMPTY_FUNCTION(0), // function section
|
|
SECTION(Table, // table section
|
|
ENTRY_COUNT(1), // 1 table
|
|
0x40, // table 0: has initializer
|
|
kRefCode, 0, // table 0: type
|
|
0, 10, // table 0: limits
|
|
kExprRefFunc, 0, kExprEnd), // table 0: initial value
|
|
SECTION(Code, ENTRY_COUNT(1), NOP_BODY)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(ValueType::Ref(0), result.value()->tables[0].type);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, NonNullableTableNoInitializer) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_x(kI32Code)),
|
|
SECTION(Table, // table section
|
|
ENTRY_COUNT(2), // 2 tables
|
|
kRefCode, 0, // table 0: type
|
|
0, 10, // table 0: limits
|
|
kRefCode, 0, // table 1: type
|
|
5, 6)}; // table 1: limits
|
|
|
|
EXPECT_FAILURE_WITH_MSG(
|
|
data, "Table of non-defaultable table (ref 0) needs initial value");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TieringCompilationHints) {
|
|
WASM_FEATURE_SCOPE(compilation_hints);
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v),
|
|
FUNCTION_SECTION(3, 0, 0, 0),
|
|
SECTION_COMPILATION_HINTS(BASELINE_TIER_BASELINE | TOP_TIER_BASELINE,
|
|
BASELINE_TIER_BASELINE | TOP_TIER_OPTIMIZED,
|
|
BASELINE_TIER_OPTIMIZED | TOP_TIER_OPTIMIZED),
|
|
SECTION(Code, ENTRY_COUNT(3), NOP_BODY, NOP_BODY, NOP_BODY),
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(3u, result.value()->compilation_hints.size());
|
|
EXPECT_EQ(WasmCompilationHintStrategy::kDefault,
|
|
result.value()->compilation_hints[0].strategy);
|
|
EXPECT_EQ(WasmCompilationHintTier::kBaseline,
|
|
result.value()->compilation_hints[0].baseline_tier);
|
|
EXPECT_EQ(WasmCompilationHintTier::kBaseline,
|
|
result.value()->compilation_hints[0].top_tier);
|
|
EXPECT_EQ(WasmCompilationHintStrategy::kDefault,
|
|
result.value()->compilation_hints[1].strategy);
|
|
EXPECT_EQ(WasmCompilationHintTier::kBaseline,
|
|
result.value()->compilation_hints[1].baseline_tier);
|
|
EXPECT_EQ(WasmCompilationHintTier::kOptimized,
|
|
result.value()->compilation_hints[1].top_tier);
|
|
EXPECT_EQ(WasmCompilationHintStrategy::kDefault,
|
|
result.value()->compilation_hints[2].strategy);
|
|
EXPECT_EQ(WasmCompilationHintTier::kOptimized,
|
|
result.value()->compilation_hints[2].baseline_tier);
|
|
EXPECT_EQ(WasmCompilationHintTier::kOptimized,
|
|
result.value()->compilation_hints[2].top_tier);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, BranchHinting) {
|
|
WASM_FEATURE_SCOPE(branch_hinting);
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), FUNCTION_SECTION(2, 0, 0),
|
|
SECTION_BRANCH_HINTS(ENTRY_COUNT(2), 0 /*func_index*/, ENTRY_COUNT(1),
|
|
3 /* if offset*/, 1 /*reserved*/, 1 /*likely*/,
|
|
1 /*func_index*/, ENTRY_COUNT(1),
|
|
5 /* br_if offset*/, 1 /*reserved*/, 0 /*unlikely*/),
|
|
SECTION(Code, ENTRY_COUNT(2),
|
|
ADD_COUNT(0, /*no locals*/
|
|
WASM_IF(WASM_I32V_1(1), WASM_NOP), WASM_END),
|
|
ADD_COUNT(0, /*no locals*/
|
|
WASM_BLOCK(WASM_BR_IF(0, WASM_I32V_1(1))), WASM_END))};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(2u, result.value()->branch_hints.size());
|
|
EXPECT_EQ(WasmBranchHint::kLikely,
|
|
result.value()->branch_hints[0].GetHintFor(3));
|
|
EXPECT_EQ(WasmBranchHint::kUnlikely,
|
|
result.value()->branch_hints[1].GetHintFor(5));
|
|
}
|
|
|
|
class WasmSignatureDecodeTest : public TestWithZone {
|
|
public:
|
|
WasmFeatures enabled_features_ = WasmFeatures::None();
|
|
|
|
const FunctionSig* DecodeSig(base::Vector<const uint8_t> bytes) {
|
|
Result<const FunctionSig*> res =
|
|
DecodeWasmSignatureForTesting(enabled_features_, zone(), bytes);
|
|
EXPECT_TRUE(res.ok()) << res.error().message() << " at offset "
|
|
<< res.error().offset();
|
|
return res.ok() ? res.value() : nullptr;
|
|
}
|
|
|
|
V8_NODISCARD testing::AssertionResult DecodeSigError(
|
|
base::Vector<const uint8_t> bytes) {
|
|
Result<const FunctionSig*> res =
|
|
DecodeWasmSignatureForTesting(enabled_features_, zone(), bytes);
|
|
if (res.ok()) {
|
|
return testing::AssertionFailure() << "unexpected valid signature";
|
|
}
|
|
return testing::AssertionSuccess();
|
|
}
|
|
};
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
|
|
static const byte data[] = {SIG_ENTRY_v_v};
|
|
v8::internal::AccountingAllocator allocator;
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(0u, sig->parameter_count());
|
|
EXPECT_EQ(0u, sig->return_count());
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(stringref);
|
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
|
ValueTypePair ret_type = kValueTypes[i];
|
|
const byte data[] = {SIG_ENTRY_x(ret_type.code)};
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
|
|
SCOPED_TRACE("Return type " + ret_type.type.name());
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(0u, sig->parameter_count());
|
|
EXPECT_EQ(1u, sig->return_count());
|
|
EXPECT_EQ(ret_type.type, sig->GetReturn());
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(stringref);
|
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
|
ValueTypePair param_type = kValueTypes[i];
|
|
const byte data[] = {SIG_ENTRY_v_x(param_type.code)};
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
|
|
SCOPED_TRACE("Param type " + param_type.type.name());
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(1u, sig->parameter_count());
|
|
EXPECT_EQ(0u, sig->return_count());
|
|
EXPECT_EQ(param_type.type, sig->GetParam(0));
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(stringref);
|
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
|
ValueTypePair ret_type = kValueTypes[i];
|
|
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
|
ValueTypePair param_type = kValueTypes[j];
|
|
const byte data[] = {SIG_ENTRY_x_x(ret_type.code, param_type.code)};
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
|
|
SCOPED_TRACE("Param type " + param_type.type.name());
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(1u, sig->parameter_count());
|
|
EXPECT_EQ(1u, sig->return_count());
|
|
EXPECT_EQ(param_type.type, sig->GetParam(0));
|
|
EXPECT_EQ(ret_type.type, sig->GetReturn());
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_i_tt) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(stringref);
|
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
|
ValueTypePair p0_type = kValueTypes[i];
|
|
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
|
ValueTypePair p1_type = kValueTypes[j];
|
|
const byte data[] = {
|
|
SIG_ENTRY_x_xx(kI32Code, p0_type.code, p1_type.code)};
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
|
|
SCOPED_TRACE("Signature i32(" + p0_type.type.name() + ", " +
|
|
p1_type.type.name() + ")");
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(2u, sig->parameter_count());
|
|
EXPECT_EQ(1u, sig->return_count());
|
|
EXPECT_EQ(p0_type.type, sig->GetParam(0));
|
|
EXPECT_EQ(p1_type.type, sig->GetParam(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_tt_tt) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(stringref);
|
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
|
ValueTypePair p0_type = kValueTypes[i];
|
|
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
|
ValueTypePair p1_type = kValueTypes[j];
|
|
const byte data[] = {SIG_ENTRY_xx_xx(p0_type.code, p1_type.code,
|
|
p0_type.code, p1_type.code)};
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
|
|
SCOPED_TRACE("p0 = " + p0_type.type.name() +
|
|
", p1 = " + p1_type.type.name());
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(2u, sig->parameter_count());
|
|
EXPECT_EQ(2u, sig->return_count());
|
|
EXPECT_EQ(p0_type.type, sig->GetParam(0));
|
|
EXPECT_EQ(p1_type.type, sig->GetParam(1));
|
|
EXPECT_EQ(p0_type.type, sig->GetReturn(0));
|
|
EXPECT_EQ(p1_type.type, sig->GetReturn(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Simd) {
|
|
WASM_FEATURE_SCOPE(simd);
|
|
const byte data[] = {SIG_ENTRY_x(kS128Code)};
|
|
if (!CheckHardwareSupportsSimd()) {
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)))
|
|
<< "Type S128 should not be allowed on this hardware";
|
|
} else {
|
|
const FunctionSig* sig = DecodeSig(base::ArrayVector(data));
|
|
ASSERT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(0u, sig->parameter_count());
|
|
EXPECT_EQ(1u, sig->return_count());
|
|
EXPECT_EQ(kWasmS128, sig->GetReturn());
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, TooManyParams) {
|
|
static const byte data[] = {kWasmFunctionTypeCode,
|
|
WASM_I32V_3(kV8MaxWasmFunctionParams + 1),
|
|
kI32Code, 0};
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, TooManyReturns) {
|
|
for (int i = 0; i < 2; i++) {
|
|
byte data[] = {kWasmFunctionTypeCode, 0,
|
|
WASM_I32V_3(kV8MaxWasmFunctionReturns + 1), kI32Code};
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
|
|
byte data[256];
|
|
for (int p = 0; p <= 255; p = p + 1 + p * 3) {
|
|
for (int i = 0; i <= p; i++) data[i] = kI32Code;
|
|
data[0] = static_cast<byte>(p);
|
|
|
|
for (int i = 0; i < p + 1; i++) {
|
|
// Should fall off the end for all signatures.
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_type) {
|
|
byte kInvalidType = 76;
|
|
for (size_t i = 0;; i++) {
|
|
byte data[] = {SIG_ENTRY_x_xx(kI32Code, kI32Code, kI32Code)};
|
|
if (i >= arraysize(data)) break;
|
|
data[i] = kInvalidType;
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_ret_type1) {
|
|
static const byte data[] = {SIG_ENTRY_x_x(kVoidCode, kI32Code)};
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type1) {
|
|
static const byte data[] = {SIG_ENTRY_x_x(kI32Code, kVoidCode)};
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type2) {
|
|
static const byte data[] = {SIG_ENTRY_x_xx(kI32Code, kI32Code, kVoidCode)};
|
|
EXPECT_TRUE(DecodeSigError(base::ArrayVector(data)));
|
|
}
|
|
|
|
class WasmFunctionVerifyTest : public TestWithIsolateAndZone {
|
|
public:
|
|
FunctionResult DecodeWasmFunction(
|
|
ModuleWireBytes wire_bytes, const WasmModule* module,
|
|
base::Vector<const uint8_t> function_bytes) {
|
|
return DecodeWasmFunctionForTesting(WasmFeatures::All(), zone(), wire_bytes,
|
|
module, function_bytes);
|
|
}
|
|
};
|
|
|
|
TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
|
static const byte data[] = {
|
|
SIG_ENTRY_v_v, // signature entry
|
|
4, // locals
|
|
3,
|
|
kI32Code, // --
|
|
4,
|
|
kI64Code, // --
|
|
5,
|
|
kF32Code, // --
|
|
6,
|
|
kF64Code, // --
|
|
kExprEnd // body
|
|
};
|
|
|
|
WasmModule module;
|
|
FunctionResult result =
|
|
DecodeWasmFunction(ModuleWireBytes({}), &module, base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
if (result.value() && result.ok()) {
|
|
WasmFunction* function = result.value().get();
|
|
EXPECT_EQ(0u, function->sig->parameter_count());
|
|
EXPECT_EQ(0u, function->sig->return_count());
|
|
EXPECT_EQ(COUNT_ARGS(SIG_ENTRY_v_v), function->code.offset());
|
|
EXPECT_EQ(sizeof(data), function->code.end_offset());
|
|
// TODO(titzer): verify encoding of local declarations
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, SectionWithoutNameLength) {
|
|
const byte data[] = {1};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, EmptyCustomSectionIsInvalid) {
|
|
// An empty custom section is invalid, because at least one byte for the
|
|
// length of the custom section name is required.
|
|
const byte data[] = {
|
|
0, // unknown section code.
|
|
0 // section length.
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, TheLoneliestOfValidModulesTheTrulyEmptyOne) {
|
|
const byte data[] = {
|
|
0, // unknown section code.
|
|
1, // section length, only one byte for the name length.
|
|
0, // string length of 0.
|
|
// Empty section name, no content, nothing but sadness.
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OnlyUnknownSectionEmpty) {
|
|
const byte data[] = {
|
|
UNKNOWN_SECTION(0),
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OnlyUnknownSectionNonEmpty) {
|
|
const byte data[] = {
|
|
UNKNOWN_SECTION(5),
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF, // section data
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, SignatureFollowedByEmptyUnknownSection) {
|
|
const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// -----------------------------------------------------------
|
|
UNKNOWN_SECTION(0)};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, SignatureFollowedByUnknownSection) {
|
|
const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// -----------------------------------------------------------
|
|
UNKNOWN_SECTION(5),
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, UnknownSectionOverflow) {
|
|
static const byte data[] = {
|
|
UNKNOWN_SECTION(9),
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
10, // 10 byte section
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, UnknownSectionUnderflow) {
|
|
static const byte data[] = {
|
|
UNKNOWN_SECTION(333),
|
|
1,
|
|
2,
|
|
3,
|
|
4, // 4 byte section
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) {
|
|
static const byte data[] = {
|
|
UNKNOWN_SECTION(1),
|
|
0, // one byte section
|
|
SECTION(Global, ENTRY_COUNT(1),
|
|
kI32Code, // memory type
|
|
0, // exported
|
|
WASM_INIT_EXPR_I32V_1(33)), // init
|
|
};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(1u, result.value()->globals.size());
|
|
EXPECT_EQ(0u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->data_segments.size());
|
|
|
|
const WasmGlobal* global = &result.value()->globals.back();
|
|
|
|
EXPECT_EQ(kWasmI32, global->type);
|
|
EXPECT_EQ(0u, global->offset);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_empty) {
|
|
static const byte data[] = {SECTION(Type, ENTRY_COUNT(0)),
|
|
SECTION(Import, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_nosigs1) {
|
|
static const byte data[] = {SECTION(Import, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) {
|
|
{
|
|
static const byte data[] = {
|
|
SECTION(Import, // section header
|
|
ENTRY_COUNT(1), // number of imports
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // global name
|
|
kExternalGlobal, // import kind
|
|
kI32Code, // type
|
|
0), // mutability
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
{
|
|
static const byte data[] = {
|
|
SECTION(Import, // section header
|
|
ENTRY_COUNT(1), // sig table
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // global name
|
|
kExternalGlobal, // import kind
|
|
kI32Code, // type
|
|
1), // mutability
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_mutability_malformed) {
|
|
static const byte data[] = {
|
|
SECTION(Import,
|
|
ENTRY_COUNT(1), // --
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('g'), // global name
|
|
kExternalGlobal, // import kind
|
|
kI32Code, // type
|
|
2), // invalid mutability
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_nosigs2) {
|
|
static const byte data[] = {
|
|
SECTION(Import, ENTRY_COUNT(1), // sig table
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // function name
|
|
kExternalFunction, // import kind
|
|
SIG_INDEX(0)), // sig index
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_invalid_sig) {
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(0)), // --
|
|
SECTION(Import, ENTRY_COUNT(1), // --
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // function name
|
|
kExternalFunction, // import kind
|
|
SIG_INDEX(0)), // sig index
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_one_sig) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
SECTION(Import,
|
|
ENTRY_COUNT(1), // --
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // function name
|
|
kExternalFunction, // import kind
|
|
SIG_INDEX(0)), // sig index
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_invalid_module) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, // --
|
|
SECTION(Import, // --
|
|
ENTRY_COUNT(1), // --
|
|
NO_NAME, // module name
|
|
ADD_COUNT('f'), // function name
|
|
kExternalFunction, // import kind
|
|
SIG_INDEX(0), // sig index
|
|
0), // auxiliary data
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ImportTable_off_end) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
SECTION(Import, ENTRY_COUNT(1),
|
|
ADD_COUNT('m'), // module name
|
|
ADD_COUNT('f'), // function name
|
|
kExternalFunction), // import kind
|
|
SIG_INDEX(0), // sig index (outside import section!)
|
|
};
|
|
|
|
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 3);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTable_empty1) {
|
|
static const byte data[] = { // signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, // --
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
SECTION(Export, ENTRY_COUNT(0)), // --
|
|
ONE_EMPTY_BODY};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(1u, result.value()->functions.size());
|
|
EXPECT_EQ(0u, result.value()->export_table.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTable_empty2) {
|
|
static const byte data[] = {SECTION(Type, ENTRY_COUNT(0)),
|
|
SECTION(Export, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTable_NoFunctions2) {
|
|
static const byte data[] = {SECTION(Export, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTableOne) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
SECTION(Export,
|
|
ENTRY_COUNT(1), // exports
|
|
NO_NAME, // --
|
|
kExternalFunction, // --
|
|
FUNC_INDEX(0)), // --
|
|
ONE_EMPTY_BODY};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(1u, result.value()->functions.size());
|
|
EXPECT_EQ(1u, result.value()->export_table.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportNameWithInvalidStringLength) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
SECTION(Export,
|
|
ENTRY_COUNT(1), // exports
|
|
U32V_1(84), // invalid string length
|
|
'e', // --
|
|
kExternalFunction, // --
|
|
FUNC_INDEX(0), // --
|
|
0, 0, 0) // auxiliary data
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTableTwo) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
SECTION(Export,
|
|
ENTRY_COUNT(2), // exports
|
|
ADD_COUNT('n', 'a', 'm', 'e'), // --
|
|
kExternalFunction, // --
|
|
FUNC_INDEX(0), // --
|
|
ADD_COUNT('n', 'o', 'm'), // --
|
|
kExternalFunction, // --
|
|
FUNC_INDEX(0)), // --
|
|
ONE_EMPTY_BODY};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(1u, result.value()->functions.size());
|
|
EXPECT_EQ(2u, result.value()->export_table.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTableThree) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, THREE_EMPTY_FUNCTIONS(SIG_INDEX(0)),
|
|
SECTION(Export,
|
|
ENTRY_COUNT(3), // exports
|
|
ADD_COUNT('a'), // --
|
|
kExternalFunction,
|
|
FUNC_INDEX(0), // --
|
|
ADD_COUNT('b'), // --
|
|
kExternalFunction,
|
|
FUNC_INDEX(1), // --
|
|
ADD_COUNT('c'), // --
|
|
kExternalFunction,
|
|
FUNC_INDEX(2)), // --
|
|
THREE_EMPTY_BODIES};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
|
|
EXPECT_EQ(3u, result.value()->functions.size());
|
|
EXPECT_EQ(3u, result.value()->export_table.size());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTableThreeOne) {
|
|
for (int i = 0; i < 6; i++) {
|
|
const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, THREE_EMPTY_FUNCTIONS(SIG_INDEX(0)),
|
|
SECTION(Export,
|
|
ENTRY_COUNT(1), // exports
|
|
ADD_COUNT('e', 'x'), // --
|
|
kExternalFunction,
|
|
FUNC_INDEX(i)), // --
|
|
THREE_EMPTY_BODIES};
|
|
|
|
if (i < 3) {
|
|
EXPECT_VERIFIES(data);
|
|
} else {
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) {
|
|
static const byte data[] = {
|
|
// signatures
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
SECTION(Export,
|
|
ENTRY_COUNT(1), // exports
|
|
NO_NAME, // --
|
|
kExternalFunction,
|
|
FUNC_INDEX(0), // --
|
|
0, 0, 0) // auxiliary data
|
|
};
|
|
|
|
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 3);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Regression_648070) {
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(0)), // --
|
|
SECTION(Function, U32V_5(3500228624)) // function count = 3500228624
|
|
}; // --
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Regression_738097) {
|
|
// The function body size caused an integer overflow in the module decoder.
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
SECTION(Code, // --
|
|
ENTRY_COUNT(1), // --
|
|
U32V_5(0xFFFFFFFF), // function size,
|
|
0) // No real body
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionBodySizeLimit) {
|
|
const uint32_t delta = 3;
|
|
for (uint32_t body_size = kV8MaxWasmFunctionSize - delta;
|
|
body_size < kV8MaxWasmFunctionSize + delta; body_size++) {
|
|
byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
kCodeSectionCode, // code section
|
|
U32V_5(1 + body_size + 5), // section size
|
|
1, // # functions
|
|
U32V_5(body_size) // body size
|
|
};
|
|
size_t total = sizeof(data) + body_size;
|
|
byte* buffer = reinterpret_cast<byte*>(calloc(1, total));
|
|
memcpy(buffer, data, sizeof(data));
|
|
ModuleResult result = DecodeModule(base::VectorOf(buffer, total));
|
|
if (body_size <= kV8MaxWasmFunctionSize) {
|
|
EXPECT_TRUE(result.ok());
|
|
} else {
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
free(buffer);
|
|
}
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, IllegalTypeCode) {
|
|
static const byte data[] = {TYPE_SECTION(1, SIG_ENTRY_v_x(0x41))};
|
|
EXPECT_FAILURE_WITH_MSG(data, "invalid value type");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionBodies_empty) {
|
|
static const byte data[] = {
|
|
EMPTY_TYPE_SECTION, // --
|
|
EMPTY_FUNCTION_SECTION, // --
|
|
EMPTY_FUNCTION_BODIES_SECTION // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionBodies_one_empty) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
ONE_EMPTY_BODY // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionBodies_one_nop) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
SECTION(Code, ENTRY_COUNT(1), NOP_BODY) // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch1) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(2, 0, 0), // --
|
|
ONE_EMPTY_BODY // --
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch2) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
SECTION(Code, ENTRY_COUNT(2), NOP_BODY, NOP_BODY) // --
|
|
};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Names_empty) {
|
|
static const byte data[] = {EMPTY_TYPE_SECTION, EMPTY_FUNCTION_SECTION,
|
|
EMPTY_FUNCTION_BODIES_SECTION,
|
|
EMPTY_NAMES_SECTION};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Names_one_empty) {
|
|
// TODO(wasm): This test does not test anything (corrupt name section does not
|
|
// fail validation).
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
ONE_EMPTY_BODY, // --
|
|
SECTION_NAMES(ENTRY_COUNT(1), FOO_STRING, NO_LOCAL_NAMES) // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Names_two_empty) {
|
|
// TODO(wasm): This test does not test anything (corrupt name section does not
|
|
// fail validation).
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(2, 0, 0), // --
|
|
TWO_EMPTY_BODIES, // --
|
|
SECTION_NAMES(ENTRY_COUNT(2), // --
|
|
FOO_STRING, NO_LOCAL_NAMES, // --
|
|
FOO_STRING, NO_LOCAL_NAMES), // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Regression684855) {
|
|
static const byte data[] = {
|
|
SECTION_NAMES(0xFB, // functions count
|
|
0x27, // |
|
|
0x00, // function name length
|
|
0xFF, // local names count
|
|
0xFF, // |
|
|
0xFF, // |
|
|
0xFF, // |
|
|
0xFF, // |
|
|
0xFF, // error: "varint too large"
|
|
0xFF, // |
|
|
0x00, // --
|
|
0x00) // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionSectionWithoutCodeSection) {
|
|
static const byte data[] = {
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // Type section.
|
|
FUNCTION_SECTION(1, 0), // Function section.
|
|
};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "function count is 1, but code section is absent");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, CodeSectionWithoutFunctionSection) {
|
|
static const byte data[] = {ONE_EMPTY_BODY};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "function body count 1 mismatch (0 expected)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, EmptyFunctionSectionWithoutCodeSection) {
|
|
static const byte data[] = {SECTION(Function, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DoubleNonEmptyFunctionSection) {
|
|
// Regression test for https://crbug.com/1342274.
|
|
static const byte data[] = {TYPE_SECTION(1, SIG_ENTRY_v_v), // --
|
|
FUNCTION_SECTION(1, 0), // --
|
|
FUNCTION_SECTION(1, 0)};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, EmptyCodeSectionWithoutFunctionSection) {
|
|
static const byte data[] = {SECTION(Code, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
// TODO(manoskouk): Reintroduce tests deleted in
|
|
// https://chromium-review.googlesource.com/c/v8/v8/+/2972910 in some other
|
|
// form.
|
|
|
|
TEST_F(WasmModuleVerifyTest, Multiple_Named_Sections) {
|
|
static const byte data[] = {
|
|
SECTION(Unknown, ADD_COUNT('X'), 17, 18), // --
|
|
SECTION(Unknown, ADD_COUNT('f', 'o', 'o'), 5, 6, 7, 8, 9), // --
|
|
SECTION(Unknown, ADD_COUNT('o', 't', 'h', 'e', 'r'), 7, 8), // --
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Section_Name_No_UTF8) {
|
|
static const byte data[] = {SECTION(Unknown, 1, 0xFF, 17, 18)};
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
class WasmModuleCustomSectionTest : public TestWithIsolateAndZone {
|
|
public:
|
|
void CheckSections(base::Vector<const uint8_t> wire_bytes,
|
|
const CustomSectionOffset* expected, size_t num_expected) {
|
|
std::vector<CustomSectionOffset> custom_sections =
|
|
DecodeCustomSections(wire_bytes);
|
|
|
|
CHECK_EQ(num_expected, custom_sections.size());
|
|
|
|
for (size_t i = 0; i < num_expected; i++) {
|
|
EXPECT_EQ(expected[i].section.offset(),
|
|
custom_sections[i].section.offset());
|
|
EXPECT_EQ(expected[i].section.length(),
|
|
custom_sections[i].section.length());
|
|
EXPECT_EQ(expected[i].name.offset(), custom_sections[i].name.offset());
|
|
EXPECT_EQ(expected[i].name.length(), custom_sections[i].name.length());
|
|
EXPECT_EQ(expected[i].payload.offset(),
|
|
custom_sections[i].payload.offset());
|
|
EXPECT_EQ(expected[i].payload.length(),
|
|
custom_sections[i].payload.length());
|
|
}
|
|
}
|
|
};
|
|
|
|
TEST_F(WasmModuleCustomSectionTest, ThreeUnknownSections) {
|
|
static constexpr byte data[] = {
|
|
U32_LE(kWasmMagic), // --
|
|
U32_LE(kWasmVersion), // --
|
|
SECTION(Unknown, 1, 'X', 17, 18), // --
|
|
SECTION(Unknown, 3, 'f', 'o', 'o', 5, 6, 7, 8, 9), // --
|
|
SECTION(Unknown, 5, 'o', 't', 'h', 'e', 'r', 7, 8), // --
|
|
};
|
|
|
|
static const CustomSectionOffset expected[] = {
|
|
// section, name, payload
|
|
{{10, 4}, {11, 1}, {12, 2}}, // --
|
|
{{16, 9}, {17, 3}, {20, 5}}, // --
|
|
{{27, 8}, {28, 5}, {33, 2}}, // --
|
|
};
|
|
|
|
CheckSections(base::ArrayVector(data), expected, arraysize(expected));
|
|
}
|
|
|
|
TEST_F(WasmModuleCustomSectionTest, TwoKnownTwoUnknownSections) {
|
|
static const byte data[] = {
|
|
U32_LE(kWasmMagic), // --
|
|
U32_LE(kWasmVersion), // --
|
|
TYPE_SECTION(2, SIG_ENTRY_v_v, SIG_ENTRY_v_v), // --
|
|
SECTION(Unknown, ADD_COUNT('X'), 17, 18), // --
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // --
|
|
SECTION(Unknown, ADD_COUNT('o', 't', 'h', 'e', 'r'), 7, 8), // --
|
|
};
|
|
|
|
static const CustomSectionOffset expected[] = {
|
|
// section, name, payload
|
|
{{19, 4}, {20, 1}, {21, 2}}, // --
|
|
{{29, 8}, {30, 5}, {35, 2}}, // --
|
|
};
|
|
|
|
CheckSections(base::ArrayVector(data), expected, arraysize(expected));
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, SourceMappingURLSection) {
|
|
static const byte data[] = {
|
|
WASM_MODULE_HEADER,
|
|
SECTION_SRC_MAP('s', 'r', 'c', '/', 'x', 'y', 'z', '.', 'c')};
|
|
ModuleResult result = DecodeModuleNoHeader(base::ArrayVector(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(WasmDebugSymbols::Type::SourceMap,
|
|
result.value()->debug_symbols.type);
|
|
ModuleWireBytes wire_bytes(base::ArrayVector(data));
|
|
WasmName external_url =
|
|
wire_bytes.GetNameOrNull(result.value()->debug_symbols.external_url);
|
|
EXPECT_EQ("src/xyz.c", std::string(external_url.data(), external_url.size()));
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, BadSourceMappingURLSection) {
|
|
static const byte data[] = {
|
|
WASM_MODULE_HEADER,
|
|
SECTION_SRC_MAP('s', 'r', 'c', '/', 'x', 0xff, 'z', '.', 'c')};
|
|
ModuleResult result = DecodeModuleNoHeader(base::ArrayVector(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(WasmDebugSymbols::Type::None, result.value()->debug_symbols.type);
|
|
EXPECT_EQ(0u, result.value()->debug_symbols.external_url.length());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleSourceMappingURLSections) {
|
|
static const byte data[] = {WASM_MODULE_HEADER,
|
|
SECTION_SRC_MAP('a', 'b', 'c'),
|
|
SECTION_SRC_MAP('p', 'q', 'r')};
|
|
ModuleResult result = DecodeModuleNoHeader(base::ArrayVector(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(WasmDebugSymbols::Type::SourceMap,
|
|
result.value()->debug_symbols.type);
|
|
ModuleWireBytes wire_bytes(base::ArrayVector(data));
|
|
WasmName external_url =
|
|
wire_bytes.GetNameOrNull(result.value()->debug_symbols.external_url);
|
|
EXPECT_EQ("abc", std::string(external_url.data(), external_url.size()));
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleNameSections) {
|
|
static const byte data[] = {
|
|
SECTION_NAMES(0, ADD_COUNT(ADD_COUNT('a', 'b', 'c'))),
|
|
SECTION_NAMES(0, ADD_COUNT(ADD_COUNT('p', 'q', 'r', 's')))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(3u, result.value()->name.length());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, BadNameSection) {
|
|
static const byte data[] = {SECTION_NAMES(
|
|
0, ADD_COUNT(ADD_COUNT('s', 'r', 'c', '/', 'x', 0xff, 'z', '.', 'c')))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(0u, result.value()->name.length());
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, PassiveDataSegment) {
|
|
static const byte data[] = {
|
|
// memory declaration ----------------------------------------------------
|
|
SECTION(Memory, ENTRY_COUNT(1), 0, 1),
|
|
// data segments --------------------------------------------------------
|
|
SECTION(Data, ENTRY_COUNT(1), PASSIVE, ADD_COUNT('h', 'i')),
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ActiveElementSegmentWithElements) {
|
|
static const byte data[] = {
|
|
// sig#0 -----------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs -----------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration -----------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// element segments -----------------------------------------------------
|
|
SECTION(Element, ENTRY_COUNT(1), ACTIVE_WITH_ELEMENTS, TABLE_INDEX0,
|
|
WASM_INIT_EXPR_I32V_1(0), kFuncRefCode, U32V_1(3),
|
|
REF_FUNC_ELEMENT(0), REF_FUNC_ELEMENT(0), REF_NULL_ELEMENT),
|
|
// code ------------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
EXPECT_VERIFIES(data);
|
|
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, PassiveElementSegment) {
|
|
static const byte data[] = {
|
|
// sig#0 -----------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs -----------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration -----------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// element segments -----------------------------------------------------
|
|
SECTION(Element, ENTRY_COUNT(1), PASSIVE_WITH_ELEMENTS, kFuncRefCode,
|
|
U32V_1(3), REF_FUNC_ELEMENT(0), REF_FUNC_ELEMENT(0),
|
|
REF_NULL_ELEMENT),
|
|
// code ------------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
EXPECT_VERIFIES(data);
|
|
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, PassiveElementSegmentExternRef) {
|
|
static const byte data[] = {
|
|
// sig#0 -----------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs -----------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration -----------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// element segments -----------------------------------------------------
|
|
SECTION(Element, ENTRY_COUNT(1), PASSIVE_WITH_ELEMENTS, kExternRefCode,
|
|
U32V_1(0)),
|
|
// code ------------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, PassiveElementSegmentWithIndices) {
|
|
static const byte data[] = {
|
|
// sig#0 -----------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs -----------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// table declaration -----------------------------------------------------
|
|
SECTION(Table, ENTRY_COUNT(1), kFuncRefCode, 0, 1),
|
|
// element segments ------------------------------------------------------
|
|
SECTION(Element, ENTRY_COUNT(1), PASSIVE, kExternalFunction,
|
|
ENTRY_COUNT(3), U32V_1(0), U32V_1(0), U32V_1(0)),
|
|
// code ------------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
EXPECT_VERIFIES(data);
|
|
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DeclarativeElementSegmentFuncRef) {
|
|
static const byte data[] = {
|
|
// sig#0 -----------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs -----------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// element segments -----------------------------------------------------
|
|
SECTION(Element, // section name
|
|
ENTRY_COUNT(1), // entry count
|
|
DECLARATIVE_WITH_ELEMENTS, // flags
|
|
kFuncRefCode, // local type
|
|
U32V_1(0)), // func ref count
|
|
// code ------------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DeclarativeElementSegmentWithInvalidIndex) {
|
|
static const byte data[] = {
|
|
// sig#0 -----------------------------------------------------------------
|
|
TYPE_SECTION_ONE_SIG_VOID_VOID,
|
|
// funcs -----------------------------------------------------------------
|
|
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
|
// element segments -----------------------------------------------------
|
|
SECTION(Element, // section name
|
|
ENTRY_COUNT(1), // entry count
|
|
DECLARATIVE, // flags
|
|
kExternalFunction, // type
|
|
ENTRY_COUNT(2), // func index count
|
|
U32V_1(0), // func index
|
|
U32V_1(1)), // func index
|
|
// code ------------------------------------------------------------------
|
|
ONE_EMPTY_BODY};
|
|
EXPECT_FAILURE_WITH_MSG(data, "function index 1 out of bounds");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSectionCorrectPlacement) {
|
|
static const byte data[] = {SECTION(Element, ENTRY_COUNT(0)),
|
|
SECTION(DataCount, ENTRY_COUNT(0)),
|
|
SECTION(Code, ENTRY_COUNT(0))};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSectionAfterCode) {
|
|
static const byte data[] = {SECTION(Code, ENTRY_COUNT(0)),
|
|
SECTION(DataCount, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result,
|
|
"The DataCount section must appear before the Code section");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSectionBeforeElement) {
|
|
static const byte data[] = {SECTION(DataCount, ENTRY_COUNT(0)),
|
|
SECTION(Element, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "unexpected section <Element>");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSectionAfterStartBeforeElement) {
|
|
static_assert(kStartSectionCode + 1 == kElementSectionCode);
|
|
static const byte data[] = {
|
|
// We need the start section for this test, but the start section must
|
|
// reference a valid function, which requires the type and function
|
|
// sections too.
|
|
TYPE_SECTION(1, SIG_ENTRY_v_v), // Type section.
|
|
FUNCTION_SECTION(1, 0), // Function section.
|
|
SECTION(Start, U32V_1(0)), // Start section.
|
|
SECTION(DataCount, ENTRY_COUNT(0)), // DataCount section.
|
|
SECTION(Element, ENTRY_COUNT(0)) // Element section.
|
|
};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "unexpected section <Element>");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleDataCountSections) {
|
|
static const byte data[] = {SECTION(DataCount, ENTRY_COUNT(0)),
|
|
SECTION(DataCount, ENTRY_COUNT(0))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "Multiple DataCount sections not allowed");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSegmentCountMatch) {
|
|
static const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), 0, 1), // Memory section.
|
|
SECTION(DataCount, ENTRY_COUNT(1)), // DataCount section.
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, // Data section.
|
|
WASM_INIT_EXPR_I32V_1(12), ADD_COUNT('h', 'i'))};
|
|
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_greater) {
|
|
static const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), 0, 1), // Memory section.
|
|
SECTION(DataCount, ENTRY_COUNT(3)), // DataCount section.
|
|
SECTION(Data, ENTRY_COUNT(0))}; // Data section.
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "data segments count 0 mismatch (3 expected)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_less) {
|
|
static const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1), 0, 1), // Memory section.
|
|
SECTION(DataCount, ENTRY_COUNT(0)), // DataCount section.
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, // Data section.
|
|
WASM_INIT_EXPR_I32V_1(12), ADD_COUNT('a', 'b', 'c'))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "data segments count 1 mismatch (0 expected)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_omitted) {
|
|
static const byte data[] = {SECTION(Memory, ENTRY_COUNT(1), 0, 1),
|
|
SECTION(DataCount, ENTRY_COUNT(1))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "data segments count 0 mismatch (1 expected)");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, GcStructIdsPass) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {SECTION(
|
|
Type, ENTRY_COUNT(1), // One recursive group...
|
|
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(3), // with three entries.
|
|
WASM_STRUCT_DEF(FIELD_COUNT(3), STRUCT_FIELD(kI32Code, true),
|
|
STRUCT_FIELD(WASM_OPT_REF(0), true),
|
|
STRUCT_FIELD(WASM_OPT_REF(1), true)),
|
|
WASM_STRUCT_DEF(FIELD_COUNT(2), STRUCT_FIELD(WASM_OPT_REF(0), true),
|
|
STRUCT_FIELD(WASM_OPT_REF(2), true)),
|
|
WASM_ARRAY_DEF(WASM_OPT_REF(0), true))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_OK(result);
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OutOfBoundsTypeInGlobal) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
static const byte data[] = {
|
|
SECTION(Global, ENTRY_COUNT(1), kRefCode, 0, WASM_REF_NULL(0), kExprEnd)};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "Type index 0 is out of bounds");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OutOfBoundsTypeInType) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1),
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kRefCode, true)))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "Type index 1 is out of bounds");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, OutOfBoundsSupertype) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), kWasmRecursiveTypeGroupCode, ENTRY_COUNT(1),
|
|
kWasmSubtypeCode, ENTRY_COUNT(1), 1,
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "type 0: supertype 1 out of bounds");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ForwardSupertypeSameType) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), kWasmRecursiveTypeGroupCode, ENTRY_COUNT(1),
|
|
kWasmSubtypeCode, ENTRY_COUNT(1), 0,
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "type 0: forward-declared supertype 0");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, ForwardSupertypeSameRecGroup) {
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
WASM_FEATURE_SCOPE(gc);
|
|
static const byte data[] = {
|
|
SECTION(Type, ENTRY_COUNT(1), kWasmRecursiveTypeGroupCode, ENTRY_COUNT(2),
|
|
kWasmSubtypeCode, ENTRY_COUNT(1), 0,
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)),
|
|
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kI32Code, true)))};
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
EXPECT_NOT_OK(result, "type 0: forward-declared supertype 0");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, IllegalPackedFields) {
|
|
WASM_FEATURE_SCOPE(gc);
|
|
WASM_FEATURE_SCOPE(typed_funcref);
|
|
|
|
static const byte data[] = {
|
|
SECTION(Global, ENTRY_COUNT(1), kI16Code, 0, WASM_INIT_EXPR_I32V_1(13))};
|
|
|
|
ModuleResult result = DecodeModule(base::ArrayVector(data));
|
|
|
|
EXPECT_NOT_OK(result, "invalid value type");
|
|
}
|
|
|
|
TEST_F(WasmModuleVerifyTest, Memory64DataSegment) {
|
|
WASM_FEATURE_SCOPE(memory64);
|
|
for (bool enable_memory64 : {false, true}) {
|
|
for (bool use_memory64 : {false, true}) {
|
|
byte const_opcode = use_memory64 ? kExprI64Const : kExprI32Const;
|
|
const byte data[] = {
|
|
SECTION(Memory, ENTRY_COUNT(1),
|
|
enable_memory64 ? kMemory64WithMaximum : kWithMaximum, 28,
|
|
28),
|
|
SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, // -
|
|
const_opcode, 0, kExprEnd, // dest addr
|
|
U32V_1(3), // source size
|
|
'a', 'b', 'c') // data bytes
|
|
};
|
|
|
|
if (enable_memory64 == use_memory64) {
|
|
EXPECT_VERIFIES(data);
|
|
} else if (enable_memory64) {
|
|
EXPECT_FAILURE_WITH_MSG(data, "expected i64, got i32");
|
|
} else {
|
|
EXPECT_FAILURE_WITH_MSG(data, "expected i32, got i64");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef EXPECT_INIT_EXPR
|
|
#undef EXPECT_INIT_EXPR_FAIL
|
|
#undef WASM_INIT_EXPR_I32V_1
|
|
#undef WASM_INIT_EXPR_I32V_2
|
|
#undef WASM_INIT_EXPR_I32V_3
|
|
#undef WASM_INIT_EXPR_I32V_4
|
|
#undef WASM_INIT_EXPR_I32V_5
|
|
#undef WASM_INIT_EXPR_F32
|
|
#undef WASM_INIT_EXPR_I64
|
|
#undef WASM_INIT_EXPR_F64
|
|
#undef WASM_INIT_EXPR_EXTERN_REF_NULL
|
|
#undef WASM_INIT_EXPR_FUNC_REF_NULL
|
|
#undef WASM_INIT_EXPR_REF_FUNC
|
|
#undef WASM_INIT_EXPR_GLOBAL
|
|
#undef REF_NULL_ELEMENT
|
|
#undef REF_FUNC_ELEMENT
|
|
#undef EMPTY_BODY
|
|
#undef NOP_BODY
|
|
#undef SIG_ENTRY_i_i
|
|
#undef UNKNOWN_SECTION
|
|
#undef ADD_COUNT
|
|
#undef SECTION
|
|
#undef TYPE_SECTION
|
|
#undef FUNCTION_SECTION
|
|
#undef FOO_STRING
|
|
#undef NO_LOCAL_NAMES
|
|
#undef EMPTY_TYPE_SECTION
|
|
#undef EMPTY_FUNCTION_SECTION
|
|
#undef EMPTY_FUNCTION_BODIES_SECTION
|
|
#undef SECTION_NAMES
|
|
#undef EMPTY_NAMES_SECTION
|
|
#undef SECTION_SRC_MAP
|
|
#undef SECTION_COMPILATION_HINTS
|
|
#undef X1
|
|
#undef X2
|
|
#undef X3
|
|
#undef X4
|
|
#undef ONE_EMPTY_FUNCTION
|
|
#undef TWO_EMPTY_FUNCTIONS
|
|
#undef THREE_EMPTY_FUNCTIONS
|
|
#undef FOUR_EMPTY_FUNCTIONS
|
|
#undef ONE_EMPTY_BODY
|
|
#undef TWO_EMPTY_BODIES
|
|
#undef THREE_EMPTY_BODIES
|
|
#undef FOUR_EMPTY_BODIES
|
|
#undef TYPE_SECTION_ONE_SIG_VOID_VOID
|
|
#undef LINEAR_MEMORY_INDEX_0
|
|
|
|
#undef FIELD_COUNT
|
|
#undef STRUCT_FIELD
|
|
#undef WASM_REF
|
|
#undef WASM_OPT_REF
|
|
#undef WASM_STRUCT_DEF
|
|
#undef WASM_ARRAY_DEF
|
|
#undef WASM_FUNCTION_DEF
|
|
#undef EXCEPTION_ENTRY
|
|
#undef EXPECT_VERIFIES
|
|
#undef EXPECT_FAILURE_LEN
|
|
#undef EXPECT_FAILURE
|
|
#undef EXPECT_OFF_END_FAILURE
|
|
#undef EXPECT_OK
|
|
#undef EXPECT_NOT_OK
|
|
|
|
} // namespace module_decoder_unittest
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|