Skip to content

Commit 4a9cc44

Browse files
authored
[gc_fuzz]: Add new GC ops to the fuzzer setup (#14196)
* Add array and left struct opcodes #1 * Add the comment for index func
1 parent 3df636a commit 4a9cc44

2 files changed

Lines changed: 202 additions & 18 deletions

File tree

crates/fuzzing/src/generators/gc_ops/ops.rs

Lines changed: 201 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::generators::gc_ops::types::StackType;
44
use crate::generators::gc_ops::{
55
limits::GcOpsLimits,
6-
types::{CompositeType, RecGroupId, TypeId, Types},
6+
types::{CompositeType, RecGroupId, StructField, TypeId, Types},
77
};
88
use mutatis::Generate;
99
use serde::{Deserialize, Serialize};
@@ -24,6 +24,21 @@ fn pick_type_index(indices: &[u32], raw: u32) -> Option<u32> {
2424
}
2525
}
2626

27+
/// Returns the element field if the indexed type is an array
28+
fn array_element<'a>(
29+
types: &'a Types,
30+
encoding_order: &[TypeId],
31+
type_index: u32,
32+
) -> Option<&'a StructField> {
33+
encoding_order
34+
.get(usize::try_from(type_index).unwrap())
35+
.and_then(|tid| types.type_defs.get(tid))
36+
.and_then(|def| match &def.composite_type {
37+
CompositeType::Array(at) => Some(&at.element),
38+
CompositeType::Struct(_) => None,
39+
})
40+
}
41+
2742
/// The base offsets and indices for various Wasm entities within
2843
/// their index spaces in the the encoded Wasm binary.
2944
#[derive(Clone, Copy)]
@@ -35,6 +50,7 @@ struct WasmEncodingBases {
3550
i31_local_idx: u32,
3651
array_local_idx: u32,
3752
typed_local_base: u32,
53+
typed_local2_base: u32,
3854
struct_global_idx: u32,
3955
eq_global_idx: u32,
4056
i31_global_idx: u32,
@@ -482,15 +498,18 @@ impl GcOps {
482498
));
483499

484500
let typed_local_base: u32 = array_local_idx + 1;
485-
for i in 0..concrete_count {
486-
let concrete = struct_type_base + i;
487-
local_decls.push((
488-
1,
489-
ValType::Ref(RefType {
490-
nullable: true,
491-
heap_type: wasm_encoder::HeapType::Concrete(concrete),
492-
}),
493-
));
501+
let typed_local2_base: u32 = typed_local_base + concrete_count;
502+
for _ in 0..2 {
503+
for i in 0..concrete_count {
504+
let concrete = struct_type_base + i;
505+
local_decls.push((
506+
1,
507+
ValType::Ref(RefType {
508+
nullable: true,
509+
heap_type: wasm_encoder::HeapType::Concrete(concrete),
510+
}),
511+
));
512+
}
494513
}
495514

496515
let storage_bases = WasmEncodingBases {
@@ -501,6 +520,7 @@ impl GcOps {
501520
i31_local_idx,
502521
array_local_idx,
503522
typed_local_base,
523+
typed_local2_base,
504524
struct_global_idx,
505525
eq_global_idx,
506526
i31_global_idx,
@@ -697,6 +717,13 @@ macro_rules! for_each_gc_op {
697717
})]
698718
StructNew { type_index: u32 },
699719

720+
#[operands([])]
721+
#[results([Struct(Some(type_index))])]
722+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
723+
type_index = pick_type_index(struct_type_indices, type_index)?;
724+
})]
725+
StructNewDefault { type_index: u32 },
726+
700727
#[operands([Some(Struct(None))])]
701728
#[results([])]
702729
TakeStructCall,
@@ -874,6 +901,13 @@ macro_rules! for_each_gc_op {
874901
})]
875902
StructGet { type_index: u32, field_index: u32 },
876903

904+
#[operands([Some(Struct(Some(type_index)))])]
905+
#[results([])]
906+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
907+
type_index = pick_type_index(struct_type_indices, type_index)?;
908+
})]
909+
StructGetU { type_index: u32, field_index: u32 },
910+
877911
#[operands([Some(Struct(Some(type_index)))])]
878912
#[results([])]
879913
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
@@ -954,13 +988,28 @@ macro_rules! for_each_gc_op {
954988
#[results([Eq])]
955989
I31RefAsEq,
956990

991+
#[operands([])]
992+
#[results([Array(Some(type_index))])]
993+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
994+
type_index = pick_type_index(array_type_indices, type_index)?;
995+
})]
996+
ArrayNewDefault { type_index: u32 },
997+
957998
#[operands([])]
958999
#[results([Array(Some(type_index))])]
9591000
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
9601001
type_index = pick_type_index(array_type_indices, type_index)?;
9611002
})]
9621003
ArrayNew { type_index: u32 },
9631004

1005+
#[operands([])]
1006+
#[results([Array(Some(type_index))])]
1007+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
1008+
n = n % (limits.array_length + 1);
1009+
type_index = pick_type_index(array_type_indices, type_index)?;
1010+
})]
1011+
ArrayNewFixed { type_index: u32, n: u32 },
1012+
9641013
#[operands([])]
9651014
#[results([Array(None)])]
9661015
NullArray,
@@ -1092,6 +1141,14 @@ macro_rules! for_each_gc_op {
10921141
})]
10931142
ArrayGet { type_index: u32, index: u32 },
10941143

1144+
#[operands([Some(Array(Some(type_index)))])]
1145+
#[results([])]
1146+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
1147+
index = index % (limits.array_length + 1);
1148+
type_index = pick_type_index(array_type_indices, type_index)?;
1149+
})]
1150+
ArrayGetU { type_index: u32, index: u32 },
1151+
10951152
#[operands([Some(Array(Some(type_index)))])]
10961153
#[results([])]
10971154
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
@@ -1100,6 +1157,25 @@ macro_rules! for_each_gc_op {
11001157
})]
11011158
ArraySet { type_index: u32, index: u32 },
11021159

1160+
#[operands([Some(Array(Some(type_index)))])]
1161+
#[results([])]
1162+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
1163+
offset = offset % (limits.array_length + 1);
1164+
len = len % (limits.array_length - offset + 2);
1165+
type_index = pick_type_index(array_type_indices, type_index)?;
1166+
})]
1167+
ArrayFill { type_index: u32, offset: u32, len: u32 },
1168+
1169+
#[operands([Some(Array(Some(type_index))), Some(Array(Some(type_index)))])]
1170+
#[results([])]
1171+
#[fixup(|limits, num_types, struct_type_indices, array_type_indices| {
1172+
dst_offset = dst_offset % (limits.array_length + 1);
1173+
src_offset = src_offset % (limits.array_length + 1);
1174+
len = len % (limits.array_length - dst_offset.max(src_offset) + 2);
1175+
type_index = pick_type_index(array_type_indices, type_index)?;
1176+
})]
1177+
ArrayCopy { type_index: u32, dst_offset: u32, src_offset: u32, len: u32 },
1178+
11031179
#[operands([Some(Array(None))])]
11041180
#[results([])]
11051181
ArrayLen,
@@ -1394,7 +1470,12 @@ impl GcOp {
13941470
}
13951471
func.instruction(&Instruction::StructNew(encoding_bases.struct_type_base + x));
13961472
}
1397-
Self::ArrayNew { type_index: x } => {
1473+
Self::StructNewDefault { type_index: x } => {
1474+
func.instruction(&Instruction::StructNewDefault(
1475+
encoding_bases.struct_type_base + x,
1476+
));
1477+
}
1478+
Self::ArrayNewDefault { type_index: x } => {
13981479
// Create a default-initialized array of a fixed length so most
13991480
// subsequent indexed accesses are in-bounds.
14001481
func.instruction(&Instruction::I32Const(
@@ -1404,6 +1485,30 @@ impl GcOp {
14041485
encoding_bases.struct_type_base + x,
14051486
));
14061487
}
1488+
Self::ArrayNew { type_index: x } => {
1489+
if let Some(element) = array_element(types, encoding_order, x) {
1490+
element
1491+
.field_type
1492+
.emit_default_const(func, type_ids_to_index);
1493+
}
1494+
func.instruction(&Instruction::I32Const(
1495+
encoding_bases.array_length.cast_signed(),
1496+
));
1497+
func.instruction(&Instruction::ArrayNew(encoding_bases.struct_type_base + x));
1498+
}
1499+
Self::ArrayNewFixed { type_index: x, n } => {
1500+
if let Some(element) = array_element(types, encoding_order, x) {
1501+
for _ in 0..n {
1502+
element
1503+
.field_type
1504+
.emit_default_const(func, type_ids_to_index);
1505+
}
1506+
}
1507+
func.instruction(&Instruction::ArrayNewFixed {
1508+
array_type_index: encoding_bases.struct_type_base + x,
1509+
array_size: n,
1510+
});
1511+
}
14071512
Self::TakeStructCall => {
14081513
func.instruction(&Instruction::Call(take_structref_idx));
14091514
}
@@ -1561,6 +1666,10 @@ impl GcOp {
15611666
Self::StructGet {
15621667
type_index,
15631668
field_index,
1669+
}
1670+
| Self::StructGetU {
1671+
type_index,
1672+
field_index,
15641673
} => {
15651674
let wasm_type = encoding_bases.struct_type_base + type_index;
15661675
let fields = encoding_order
@@ -1582,10 +1691,17 @@ impl GcOp {
15821691
func.instruction(&Instruction::LocalGet(typed_local));
15831692
let idx = field_index % u32::try_from(fields.len()).unwrap();
15841693
if fields[usize::try_from(idx).unwrap()].field_type.is_packed() {
1585-
func.instruction(&Instruction::StructGetS {
1586-
struct_type_index: wasm_type,
1587-
field_index: idx,
1588-
});
1694+
if matches!(self, Self::StructGetU { .. }) {
1695+
func.instruction(&Instruction::StructGetU {
1696+
struct_type_index: wasm_type,
1697+
field_index: idx,
1698+
});
1699+
} else {
1700+
func.instruction(&Instruction::StructGetS {
1701+
struct_type_index: wasm_type,
1702+
field_index: idx,
1703+
});
1704+
}
15891705
} else {
15901706
func.instruction(&Instruction::StructGet {
15911707
struct_type_index: wasm_type,
@@ -1767,7 +1883,7 @@ impl GcOp {
17671883
func.instruction(&Instruction::LocalGet(encoding_bases.array_local_idx));
17681884
func.instruction(&Instruction::TableSet(encoding_bases.array_table_idx));
17691885
}
1770-
Self::ArrayGet { type_index, index } => {
1886+
Self::ArrayGet { type_index, index } | Self::ArrayGetU { type_index, index } => {
17711887
let wasm_type = encoding_bases.struct_type_base + type_index;
17721888
let typed_local = encoding_bases.typed_local_base + type_index;
17731889
let element = encoding_order
@@ -1789,7 +1905,11 @@ impl GcOp {
17891905
func.instruction(&Instruction::LocalGet(typed_local));
17901906
func.instruction(&Instruction::I32Const(index.cast_signed()));
17911907
if element.field_type.is_packed() {
1792-
func.instruction(&Instruction::ArrayGetS(wasm_type));
1908+
if matches!(self, Self::ArrayGetU { .. }) {
1909+
func.instruction(&Instruction::ArrayGetU(wasm_type));
1910+
} else {
1911+
func.instruction(&Instruction::ArrayGetS(wasm_type));
1912+
}
17931913
} else {
17941914
func.instruction(&Instruction::ArrayGet(wasm_type));
17951915
}
@@ -1834,6 +1954,70 @@ impl GcOp {
18341954
}
18351955
}
18361956
}
1957+
Self::ArrayFill {
1958+
type_index,
1959+
offset,
1960+
len,
1961+
} => {
1962+
let wasm_type = encoding_bases.struct_type_base + type_index;
1963+
let typed_local = encoding_bases.typed_local_base + type_index;
1964+
match array_element(types, encoding_order, type_index) {
1965+
Some(element) if element.mutable => {
1966+
func.instruction(&Instruction::LocalTee(typed_local));
1967+
func.instruction(&Instruction::RefIsNull);
1968+
func.instruction(&Instruction::If(wasm_encoder::BlockType::Empty));
1969+
func.instruction(&Instruction::Else);
1970+
func.instruction(&Instruction::LocalGet(typed_local));
1971+
func.instruction(&Instruction::I32Const(offset.cast_signed()));
1972+
element
1973+
.field_type
1974+
.emit_default_const(func, type_ids_to_index);
1975+
func.instruction(&Instruction::I32Const(len.cast_signed()));
1976+
func.instruction(&Instruction::ArrayFill(wasm_type));
1977+
func.instruction(&Instruction::End);
1978+
}
1979+
_ => {
1980+
func.instruction(&Instruction::Drop);
1981+
}
1982+
}
1983+
}
1984+
Self::ArrayCopy {
1985+
type_index,
1986+
dst_offset,
1987+
src_offset,
1988+
len,
1989+
} => {
1990+
let wasm_type = encoding_bases.struct_type_base + type_index;
1991+
let dst_local = encoding_bases.typed_local_base + type_index;
1992+
let src_local = encoding_bases.typed_local2_base + type_index;
1993+
match array_element(types, encoding_order, type_index) {
1994+
Some(element) if element.mutable => {
1995+
func.instruction(&Instruction::LocalSet(src_local));
1996+
func.instruction(&Instruction::LocalSet(dst_local));
1997+
func.instruction(&Instruction::LocalGet(dst_local));
1998+
func.instruction(&Instruction::RefIsNull);
1999+
func.instruction(&Instruction::LocalGet(src_local));
2000+
func.instruction(&Instruction::RefIsNull);
2001+
func.instruction(&Instruction::I32Or);
2002+
func.instruction(&Instruction::If(wasm_encoder::BlockType::Empty));
2003+
func.instruction(&Instruction::Else);
2004+
func.instruction(&Instruction::LocalGet(dst_local));
2005+
func.instruction(&Instruction::I32Const(dst_offset.cast_signed()));
2006+
func.instruction(&Instruction::LocalGet(src_local));
2007+
func.instruction(&Instruction::I32Const(src_offset.cast_signed()));
2008+
func.instruction(&Instruction::I32Const(len.cast_signed()));
2009+
func.instruction(&Instruction::ArrayCopy {
2010+
array_type_index_dst: wasm_type,
2011+
array_type_index_src: wasm_type,
2012+
});
2013+
func.instruction(&Instruction::End);
2014+
}
2015+
_ => {
2016+
func.instruction(&Instruction::Drop);
2017+
func.instruction(&Instruction::Drop);
2018+
}
2019+
}
2020+
}
18372021
Self::ArrayLen => {
18382022
// array.len traps on null, so guard; the length is not tracked.
18392023
func.instruction(&Instruction::LocalTee(encoding_bases.array_local_idx));

crates/fuzzing/src/generators/gc_ops/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,7 @@ impl StackType {
12221222
);
12231223
let t = Self::clamp(t, num_types);
12241224
Self::emit(
1225-
GcOp::ArrayNew { type_index: t },
1225+
GcOp::ArrayNewDefault { type_index: t },
12261226
stack,
12271227
out,
12281228
num_types,

0 commit comments

Comments
 (0)