Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions src/wasm/wasm-validator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3868,6 +3868,11 @@ void FunctionValidator::visitArraySet(ArraySet* curr) {
shouldBeTrue(element.mutable_, curr, "array.set type must be mutable");
}

static bool isValidMultibyteElement(const Field& element) {
return element.packedType == Field::i8 || element.packedType == Field::i16 ||
(element.packedType == Field::NotPacked && element.type.isNumber());
}

void FunctionValidator::visitArrayLoad(ArrayLoad* curr) {
shouldBeTrue(getModule()->features.hasMultibyte(),
curr,
Expand All @@ -3876,6 +3881,10 @@ void FunctionValidator::visitArrayLoad(ArrayLoad* curr) {
Type(Type::i32),
curr,
"array load index must be an i32");
validateMemBytes(curr->bytes, curr->type, curr);
validateOffset(curr->offset, nullptr, curr);
validateAlignment(
curr->align, curr->type, curr->bytes, /*isAtomic=*/false, curr);
if (curr->type == Type::unreachable) {
return;
}
Expand All @@ -3889,8 +3898,9 @@ void FunctionValidator::visitArrayLoad(ArrayLoad* curr) {

auto heapType = curr->ref->type.getHeapType();
const auto& element = heapType.getArray().element;
shouldBeTrue(
element.packedType == Field::i8, curr, "array load type must be i8");
shouldBeTrue(isValidMultibyteElement(element),
curr,
"array load type must be a numeric type");
}

void FunctionValidator::visitArrayStore(ArrayStore* curr) {
Expand All @@ -3901,6 +3911,10 @@ void FunctionValidator::visitArrayStore(ArrayStore* curr) {
Type(Type::i32),
curr,
"array store index must be an i32");
validateMemBytes(curr->bytes, curr->value->type, curr);
validateOffset(curr->offset, nullptr, curr);
validateAlignment(
curr->align, curr->value->type, curr->bytes, /*isAtomic=*/false, curr);
if (curr->type == Type::unreachable) {
return;
}
Expand All @@ -3914,8 +3928,9 @@ void FunctionValidator::visitArrayStore(ArrayStore* curr) {

auto heapType = curr->ref->type.getHeapType();
const auto& element = heapType.getArray().element;
shouldBeTrue(
element.packedType == Field::i8, curr, "array store type must be i8");
shouldBeTrue(isValidMultibyteElement(element),
curr,
"array store type must be a numeric type");
shouldBeTrue(element.mutable_, curr, "array store type must be mutable");
}

Expand Down Expand Up @@ -4842,7 +4857,8 @@ void FunctionValidator::visitFunction(Function* curr) {
void FunctionValidator::validateOffset(Address offset,
Memory* mem,
Expression* curr) {
shouldBeTrue(mem->is64() || offset <= std::numeric_limits<uint32_t>::max(),
shouldBeTrue((mem && mem->is64()) ||
offset <= std::numeric_limits<uint32_t>::max(),
curr,
"offset must be u32");
}
Expand Down
241 changes: 228 additions & 13 deletions test/lit/array-multibyte.wast
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,52 @@
;; RTRIP: (type $i8_array (array (mut i8)))
(type $i8_array (array (mut i8)))

;; CHECK: (type $2 (func (param (ref $i8_array))))
;; CHECK: (type $i16_array (array (mut i16)))

;; CHECK: (type $i32_array (array (mut i32)))

;; CHECK: (type $i64_array (array (mut i64)))

;; CHECK: (type $f32_array (array (mut f32)))

;; CHECK: (type $f64_array (array (mut f64)))

;; CHECK: (type $v128_array (array (mut v128)))

;; CHECK: (type $imm_i8_array (array i8))

;; CHECK: (type $imm_i32_array (array i32))

;; CHECK: (type $10 (func (param (ref $i16_array) (ref $i32_array) (ref $i64_array) (ref $f32_array) (ref $f64_array) (ref $v128_array))))

;; CHECK: (type $11 (func (param (ref $i8_array))))

;; CHECK: (type $12 (func (param (ref $imm_i8_array) (ref $imm_i32_array))))

;; CHECK: (global $arr (ref $i8_array) (array.new_default $i8_array
;; CHECK-NEXT: (i32.const 4)
;; CHECK-NEXT: ))
;; RTRIP: (type $2 (func (param (ref $i8_array))))
;; RTRIP: (type $i16_array (array (mut i16)))

;; RTRIP: (type $i32_array (array (mut i32)))

;; RTRIP: (type $i64_array (array (mut i64)))

;; RTRIP: (type $f32_array (array (mut f32)))

;; RTRIP: (type $f64_array (array (mut f64)))

;; RTRIP: (type $v128_array (array (mut v128)))

;; RTRIP: (type $imm_i8_array (array i8))

;; RTRIP: (type $imm_i32_array (array i32))

;; RTRIP: (type $10 (func (param (ref $i16_array) (ref $i32_array) (ref $i64_array) (ref $f32_array) (ref $f64_array) (ref $v128_array))))

;; RTRIP: (type $11 (func (param (ref $i8_array))))

;; RTRIP: (type $12 (func (param (ref $imm_i8_array) (ref $imm_i32_array))))

;; RTRIP: (global $arr (ref $i8_array) (array.new_default $i8_array
;; RTRIP-NEXT: (i32.const 4)
Expand Down Expand Up @@ -995,25 +1035,167 @@
(i32.store8 (type $i8_array) (global.get $arr) (i32.const 1) (unreachable))
)

;; CHECK: (func $loads_index_unreachable (type $0)
(type $i16_array (array (mut i16)))
(type $i32_array (array (mut i32)))
(type $i64_array (array (mut i64)))
(type $f32_array (array (mut f32)))
(type $f64_array (array (mut f64)))
(type $v128_array (array (mut v128)))
(type $imm_i8_array (array i8))
(type $imm_i32_array (array i32))

;; CHECK: (func $expanded_types (type $10) (param $a16 (ref $i16_array)) (param $a32 (ref $i32_array)) (param $a64 (ref $i64_array)) (param $af32 (ref $f32_array)) (param $af64 (ref $f64_array)) (param $av (ref $v128_array))
;; CHECK-NEXT: (i32.store16 (type $i16_array)
;; CHECK-NEXT: (local.get $a16)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.load (type $i8_array)
;; CHECK-NEXT: (global.get $arr)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i32.load16_u (type $i16_array)
;; CHECK-NEXT: (local.get $a16)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.store (type $i32_array)
;; CHECK-NEXT: (local.get $a32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.load (type $i32_array)
;; CHECK-NEXT: (local.get $a32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i64.store (type $i64_array)
;; CHECK-NEXT: (local.get $a64)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load (type $i64_array)
;; CHECK-NEXT: (local.get $a64)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (f32.store (type $f32_array)
;; CHECK-NEXT: (local.get $af32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (f32.const 4)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (f32.load (type $f32_array)
;; CHECK-NEXT: (local.get $af32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (f64.store (type $f64_array)
;; CHECK-NEXT: (local.get $af64)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (f64.const 5)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (f64.load (type $f64_array)
;; CHECK-NEXT: (local.get $af64)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (v128.store (type $v128_array)
;; CHECK-NEXT: (local.get $av)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (v128.load (type $v128_array)
;; CHECK-NEXT: (local.get $av)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; RTRIP: (func $loads_index_unreachable (type $0)
;; RTRIP: (func $expanded_types (type $10) (param $a16 (ref $i16_array)) (param $a32 (ref $i32_array)) (param $a64 (ref $i64_array)) (param $af32 (ref $f32_array)) (param $af64 (ref $f64_array)) (param $av (ref $v128_array))
;; RTRIP-NEXT: (i32.store16 (type $i16_array)
;; RTRIP-NEXT: (local.get $a16)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: (i32.const 1)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (global.get $arr)
;; RTRIP-NEXT: (i32.load16_u (type $i16_array)
;; RTRIP-NEXT: (local.get $a16)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (i32.store (type $i32_array)
;; RTRIP-NEXT: (local.get $a32)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: (i32.const 2)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (i32.load (type $i32_array)
;; RTRIP-NEXT: (local.get $a32)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (i64.store (type $i64_array)
;; RTRIP-NEXT: (local.get $a64)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: (i64.const 3)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (i64.load (type $i64_array)
;; RTRIP-NEXT: (local.get $a64)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (f32.store (type $f32_array)
;; RTRIP-NEXT: (local.get $af32)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: (f32.const 4)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (f32.load (type $f32_array)
;; RTRIP-NEXT: (local.get $af32)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (f64.store (type $f64_array)
;; RTRIP-NEXT: (local.get $af64)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: (f64.const 5)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (f64.load (type $f64_array)
;; RTRIP-NEXT: (local.get $af64)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (v128.store (type $v128_array)
;; RTRIP-NEXT: (local.get $av)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (v128.load (type $v128_array)
;; RTRIP-NEXT: (local.get $av)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (unreachable)
;; RTRIP-NEXT: )
(func $loads_index_unreachable
(drop (i32.load8_u (type $i8_array) (global.get $arr) (unreachable)))
(func $expanded_types (param $a16 (ref $i16_array)) (param $a32 (ref $i32_array)) (param $a64 (ref $i64_array)) (param $af32 (ref $f32_array)) (param $af64 (ref $f64_array)) (param $av (ref $v128_array))
(i32.store16 (type $i16_array) (local.get $a16) (i32.const 0) (i32.const 1))
(drop (i32.load16_u (type $i16_array) (local.get $a16) (i32.const 0)))
(i32.store (type $i32_array) (local.get $a32) (i32.const 0) (i32.const 2))
(drop (i32.load (type $i32_array) (local.get $a32) (i32.const 0)))
(i64.store (type $i64_array) (local.get $a64) (i32.const 0) (i64.const 3))
(drop (i64.load (type $i64_array) (local.get $a64) (i32.const 0)))
(f32.store (type $f32_array) (local.get $af32) (i32.const 0) (f32.const 4.0))
(drop (f32.load (type $f32_array) (local.get $af32) (i32.const 0)))
(f64.store (type $f64_array) (local.get $af64) (i32.const 0) (f64.const 5.0))
(drop (f64.load (type $f64_array) (local.get $af64) (i32.const 0)))
(v128.store (type $v128_array) (local.get $av) (i32.const 0) (v128.const i32x4 1 2 3 4))
(drop (v128.load (type $v128_array) (local.get $av) (i32.const 0)))
)

;; CHECK: (func $immediates (type $2) (param $arr (ref $i8_array))
;; CHECK: (func $immediates (type $11) (param $arr (ref $i8_array))
;; CHECK-NEXT: (i32.store8 (type $i8_array) offset=4
;; CHECK-NEXT: (local.get $arr)
;; CHECK-NEXT: (i32.const 0)
Expand Down Expand Up @@ -1048,7 +1230,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; RTRIP: (func $immediates (type $2) (param $arr (ref $i8_array))
;; RTRIP: (func $immediates (type $11) (param $arr (ref $i8_array))
;; RTRIP-NEXT: (i32.store8 (type $i8_array) offset=4
;; RTRIP-NEXT: (local.get $arr)
;; RTRIP-NEXT: (i32.const 0)
Expand Down Expand Up @@ -1091,4 +1273,37 @@
(drop (i32.load (type $i8_array) offset=8 align=4 (local.get $arr) (i32.const 0)))
(drop (i32.load (type $i8_array) offset=12 align=2 (local.get $arr) (i32.const 0)))
)

;; CHECK: (func $immutable_loads (type $12) (param $imm8 (ref $imm_i8_array)) (param $imm32 (ref $imm_i32_array))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.load8_u (type $imm_i8_array)
;; CHECK-NEXT: (local.get $imm8)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.load (type $imm_i32_array)
;; CHECK-NEXT: (local.get $imm32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; RTRIP: (func $immutable_loads (type $12) (param $imm8 (ref $imm_i8_array)) (param $imm32 (ref $imm_i32_array))
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (i32.load8_u (type $imm_i8_array)
;; RTRIP-NEXT: (local.get $imm8)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: (drop
;; RTRIP-NEXT: (i32.load (type $imm_i32_array)
;; RTRIP-NEXT: (local.get $imm32)
;; RTRIP-NEXT: (i32.const 0)
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
;; RTRIP-NEXT: )
(func $immutable_loads (param $imm8 (ref $imm_i8_array)) (param $imm32 (ref $imm_i32_array))
(drop (i32.load8_u (type $imm_i8_array) (local.get $imm8) (i32.const 0)))
(drop (i32.load (type $imm_i32_array) (local.get $imm32) (i32.const 0)))
)
)
31 changes: 31 additions & 0 deletions test/lit/validation/array-multibyte-invalid.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
;; RUN: not wasm-opt -all %s 2>&1 | filecheck %s

(module
(type $imm (array i8))
(type $any_arr (array (mut anyref)))

;; CHECK: unexpected false: array store type must be mutable
(func $store-immutable (param $a (ref $imm))
(i32.store8 (type $imm) (local.get $a) (i32.const 0) (i32.const 0))
)

;; CHECK: unexpected false: array load type must be a numeric type
(func $load-non-numeric (param $a (ref $any_arr))
(drop (i32.load8_u (type $any_arr) (local.get $a) (i32.const 0)))
)

;; CHECK: unexpected false: array store type must be a numeric type
(func $store-non-numeric (param $a (ref $any_arr))
(i32.store8 (type $any_arr) (local.get $a) (i32.const 0) (i32.const 0))
)

;; CHECK: unexpected false: alignment must not exceed natural
(func $bad-align (param $a (ref $imm))
(drop (i32.load8_u (type $imm) align=2 (local.get $a) (i32.const 0)))
)

;; CHECK: unexpected false: offset must be u32
(func $bad-offset (param $a (ref $imm))
(drop (i32.load8_u (type $imm) offset=4294967296 (local.get $a) (i32.const 0)))
)
)
Loading