1mod code_builder;
4pub(crate) mod encode;
5mod terminate;
6
7use crate::{Config, arbitrary_loop, limited_string, unique_string};
8use arbitrary::{Arbitrary, Result, Unstructured};
9use code_builder::CodeBuilderAllocations;
10use flagset::{FlagSet, flags};
11use std::collections::{HashMap, HashSet};
12use std::fmt;
13use std::mem;
14use std::ops::Range;
15use std::rc::Rc;
16use std::str::{self, FromStr};
17use wasm_encoder::{
18 AbstractHeapType, ArrayType, BlockType, ConstExpr, Encode, ExportKind, FieldType, HeapType,
19 RefType, StorageType, StructType, ValType,
20};
21pub(crate) use wasm_encoder::{GlobalType, MemoryType, TableType};
22
23const CHANCE_OFFSET_INBOUNDS: usize = 10; const CHANCE_SEGMENT_ON_EMPTY: usize = 10; const PCT_INBOUNDS: f64 = 0.995; type Instruction = wasm_encoder::Instruction<'static>;
34
35pub struct Module {
47 config: Config,
48 duplicate_imports_behavior: DuplicateImportsBehavior,
49 valtypes: Vec<ValType>,
50
51 types: Vec<SubType>,
54
55 rec_groups: Vec<Range<usize>>,
59
60 super_to_sub_types: HashMap<u32, Vec<u32>>,
62
63 can_subtype: Vec<u32>,
65
66 should_encode_types: bool,
68
69 must_share: bool,
72
73 imports: Vec<Imports>,
77
78 should_encode_imports: bool,
81
82 array_types: Vec<u32>,
84
85 func_types: Vec<u32>,
87
88 struct_types: Vec<u32>,
90
91 num_imports: usize,
93
94 num_defined_tags: usize,
97
98 num_defined_funcs: usize,
101
102 defined_tables: Vec<Option<ConstExpr>>,
104
105 num_defined_memories: usize,
108
109 defined_globals: Vec<(u32, ConstExpr)>,
112
113 tags: Vec<TagType>,
116
117 funcs: Vec<(u32, Rc<FuncType>)>,
121
122 tables: Vec<TableType>,
125
126 globals: Vec<GlobalType>,
129
130 memories: Vec<MemoryType>,
133
134 exports: Vec<(String, ExportKind, u32)>,
135 start: Option<u32>,
136 elems: Vec<ElementSegment>,
137 code: Vec<Code>,
138 data: Vec<DataSegment>,
139
140 type_size: u32,
143
144 export_names: HashSet<String>,
146
147 max_type_limit: MaxTypeLimit,
149
150 interesting_values32: Vec<u32>,
153 interesting_values64: Vec<u64>,
154}
155
156impl<'a> Arbitrary<'a> for Module {
157 fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
158 Module::new(Config::default(), u)
159 }
160}
161
162impl fmt::Debug for Module {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 f.debug_struct("Module")
165 .field("config", &self.config)
166 .field(&"...", &"...")
167 .finish()
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub(crate) enum DuplicateImportsBehavior {
173 Allowed,
174 #[cfg_attr(
175 not(feature = "component-model"),
176 expect(
177 dead_code,
178 reason = "Core WebAssembly permits duplicate import module/name pairs"
179 )
180 )]
181 Disallowed,
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185enum AllowEmptyRecGroup {
186 Yes,
187 No,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191enum MaxTypeLimit {
192 ModuleTypes,
193 Num(u32),
194}
195
196impl Module {
197 pub fn config(&self) -> &Config {
199 &self.config
200 }
201
202 pub fn new(config: Config, u: &mut Unstructured<'_>) -> Result<Self> {
205 Self::new_internal(config, u, DuplicateImportsBehavior::Allowed)
206 }
207
208 pub(crate) fn new_internal(
209 config: Config,
210 u: &mut Unstructured<'_>,
211 duplicate_imports_behavior: DuplicateImportsBehavior,
212 ) -> Result<Self> {
213 let mut module = Module::empty(config, duplicate_imports_behavior);
214 module.build(u)?;
215 Ok(module)
216 }
217
218 fn empty(mut config: Config, duplicate_imports_behavior: DuplicateImportsBehavior) -> Self {
219 config.sanitize();
220 Module {
221 config,
222 duplicate_imports_behavior,
223 valtypes: Vec::new(),
224 types: Vec::new(),
225 rec_groups: Vec::new(),
226 can_subtype: Vec::new(),
227 super_to_sub_types: HashMap::new(),
228 should_encode_types: false,
229 imports: Vec::new(),
230 should_encode_imports: false,
231 array_types: Vec::new(),
232 func_types: Vec::new(),
233 struct_types: Vec::new(),
234 num_imports: 0,
235 num_defined_tags: 0,
236 num_defined_funcs: 0,
237 defined_tables: Vec::new(),
238 num_defined_memories: 0,
239 defined_globals: Vec::new(),
240 tags: Vec::new(),
241 funcs: Vec::new(),
242 tables: Vec::new(),
243 globals: Vec::new(),
244 memories: Vec::new(),
245 exports: Vec::new(),
246 start: None,
247 elems: Vec::new(),
248 code: Vec::new(),
249 data: Vec::new(),
250 type_size: 0,
251 export_names: HashSet::new(),
252 max_type_limit: MaxTypeLimit::ModuleTypes,
253 interesting_values32: Vec::new(),
254 interesting_values64: Vec::new(),
255 must_share: false,
256 }
257 }
258}
259
260#[derive(Clone, Debug, PartialEq, Eq, Hash)]
261pub(crate) struct SubType {
262 pub(crate) is_final: bool,
263 pub(crate) supertype: Option<u32>,
264 pub(crate) composite_type: CompositeType,
265 depth: u32,
268}
269
270impl SubType {
271 fn unwrap_struct(&self) -> &StructType {
272 self.composite_type.unwrap_struct()
273 }
274
275 fn unwrap_func(&self) -> &Rc<FuncType> {
276 self.composite_type.unwrap_func()
277 }
278
279 fn unwrap_array(&self) -> &ArrayType {
280 self.composite_type.unwrap_array()
281 }
282}
283
284#[derive(Clone, Debug, PartialEq, Eq, Hash)]
285pub(crate) struct CompositeType {
286 pub inner: CompositeInnerType,
287 pub shared: bool,
288 pub descriptor: Option<u32>,
289 pub describes: Option<u32>,
290}
291
292impl CompositeType {
293 #[cfg(any(feature = "component-model", feature = "wasmparser"))]
294 pub(crate) fn new_func(func: Rc<FuncType>, shared: bool) -> Self {
295 Self {
296 inner: CompositeInnerType::Func(func),
297 shared,
298 descriptor: None,
299 describes: None,
300 }
301 }
302
303 fn unwrap_func(&self) -> &Rc<FuncType> {
304 match &self.inner {
305 CompositeInnerType::Func(f) => f,
306 _ => panic!("not a func"),
307 }
308 }
309
310 fn unwrap_array(&self) -> &ArrayType {
311 match &self.inner {
312 CompositeInnerType::Array(a) => a,
313 _ => panic!("not an array"),
314 }
315 }
316
317 fn unwrap_struct(&self) -> &StructType {
318 match &self.inner {
319 CompositeInnerType::Struct(s) => s,
320 _ => panic!("not a struct"),
321 }
322 }
323}
324
325impl From<&CompositeType> for wasm_encoder::CompositeType {
326 fn from(ty: &CompositeType) -> Self {
327 let inner = match &ty.inner {
328 CompositeInnerType::Array(a) => wasm_encoder::CompositeInnerType::Array(*a),
329 CompositeInnerType::Func(f) => wasm_encoder::CompositeInnerType::Func(
330 wasm_encoder::FuncType::new(f.params.iter().cloned(), f.results.iter().cloned()),
331 ),
332 CompositeInnerType::Struct(s) => wasm_encoder::CompositeInnerType::Struct(s.clone()),
333 };
334 wasm_encoder::CompositeType {
335 shared: ty.shared,
336 inner,
337 descriptor: ty.descriptor,
338 describes: ty.describes,
339 }
340 }
341}
342
343#[derive(Clone, Debug, PartialEq, Eq, Hash)]
344pub(crate) enum CompositeInnerType {
345 Array(ArrayType),
346 Func(Rc<FuncType>),
347 Struct(StructType),
348}
349
350#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
352pub(crate) struct FuncType {
353 pub(crate) params: Vec<ValType>,
355 pub(crate) results: Vec<ValType>,
357}
358
359#[derive(Clone, Debug, PartialEq, Eq, Hash)]
361pub(crate) struct Import {
362 pub(crate) module: String,
364 pub(crate) name: String,
366 pub(crate) entity_type: EntityType,
368}
369
370#[derive(Clone, Debug, PartialEq, Eq, Hash)]
371pub(crate) enum Imports {
372 Single(Import),
373 Compact1 {
374 module: String,
375 items: Vec<Import>,
376 },
377 Compact2 {
378 module: String,
379 entity_type: EntityType,
380 names: Vec<String>,
381 },
382}
383
384#[derive(Arbitrary)]
385enum ImportsKind {
386 Single,
387 Compact1,
388 Compact2,
389}
390
391#[derive(Clone, Debug, PartialEq, Eq, Hash)]
393pub(crate) enum EntityType {
394 Global(GlobalType),
396 Table(TableType),
398 Memory(MemoryType),
400 Tag(TagType),
402 Func(u32, Rc<FuncType>),
404}
405
406#[derive(Clone, Debug, PartialEq, Eq, Hash)]
408pub(crate) struct TagType {
409 func_type_idx: u32,
411 func_type: Rc<FuncType>,
413}
414
415#[derive(Debug)]
416struct ElementSegment {
417 kind: ElementKind,
418 ty: RefType,
419 items: Elements,
420}
421
422#[derive(Debug)]
423enum ElementKind {
424 Passive,
425 Declared,
426 Active {
427 table: Option<u32>, offset: Offset,
429 },
430}
431
432#[derive(Debug)]
433enum Elements {
434 Functions(Vec<u32>),
435 Expressions(Vec<ConstExpr>),
436}
437
438#[derive(Debug)]
439struct Code {
440 locals: Vec<ValType>,
441 instructions: Instructions,
442}
443
444#[derive(Debug)]
445enum Instructions {
446 Generated(Vec<Instruction>),
447 Arbitrary(Vec<u8>),
448}
449
450#[derive(Debug)]
451struct DataSegment {
452 kind: DataSegmentKind,
453 init: Vec<u8>,
454}
455
456#[derive(Debug)]
457enum DataSegmentKind {
458 Passive,
459 Active { memory_index: u32, offset: Offset },
460}
461
462#[derive(Debug)]
463pub(crate) enum Offset {
464 Const32(i32),
465 Const64(i64),
466 Global(u32),
467}
468
469impl Module {
470 fn build(&mut self, u: &mut Unstructured) -> Result<()> {
471 self.valtypes = configured_valtypes(&self.config);
472
473 let mut generate_arbitrary_imports = true;
474 let mut generate_arbitrary_exports = true;
475 if self.imports_exports_from_module_shape(u)? {
476 generate_arbitrary_imports = false;
477 generate_arbitrary_exports = false;
478 }
479 if self.arbitrary_imports_from_available(u)? {
488 generate_arbitrary_imports = false;
489 }
490 self.arbitrary_types(u)?;
491 if generate_arbitrary_imports {
492 self.arbitrary_imports(u)?;
493 }
494
495 self.should_encode_imports = !self.imports.is_empty() || u.arbitrary()?;
496
497 self.arbitrary_tags(u)?;
498 self.arbitrary_funcs(u)?;
499 self.arbitrary_tables(u)?;
500 self.arbitrary_memories(u)?;
501 self.arbitrary_globals(u)?;
502 if self.required_exports(u)? {
503 generate_arbitrary_exports = false;
504 }
505 if generate_arbitrary_exports {
506 self.arbitrary_exports(u)?;
507 }
508 self.should_encode_types = !self.types.is_empty() || u.arbitrary()?;
509 self.arbitrary_start(u)?;
510 self.arbitrary_elems(u)?;
511 self.arbitrary_data(u)?;
512 self.arbitrary_code(u)?;
513 Ok(())
514 }
515
516 #[inline]
517 fn val_type_is_sub_type(&self, a: ValType, b: ValType) -> bool {
518 match (a, b) {
519 (a, b) if a == b => true,
520 (ValType::Ref(a), ValType::Ref(b)) => self.ref_type_is_sub_type(a, b),
521 _ => false,
522 }
523 }
524
525 fn ref_type_is_sub_type(&self, a: RefType, b: RefType) -> bool {
527 if a == b {
528 return true;
529 }
530
531 if a.nullable && !b.nullable {
532 return false;
533 }
534
535 self.heap_type_is_sub_type(a.heap_type, b.heap_type)
536 }
537
538 fn heap_type_is_sub_type(&self, a: HeapType, b: HeapType) -> bool {
539 use AbstractHeapType::*;
540 use CompositeInnerType as CT;
541 use HeapType as HT;
542 match (a, b) {
543 (a, b) if a == b => true,
544
545 (
546 HT::Abstract {
547 shared: a_shared,
548 ty: a_ty,
549 },
550 HT::Abstract {
551 shared: b_shared,
552 ty: b_ty,
553 },
554 ) => {
555 a_shared == b_shared
556 && match (a_ty, b_ty) {
557 (Eq | I31 | Struct | Array | None, Any) => true,
558 (I31 | Struct | Array | None, Eq) => true,
559 (NoExtern, Extern) => true,
560 (NoFunc, Func) => true,
561 (None, I31 | Array | Struct) => true,
562 (NoExn, Exn) => true,
563 _ => false,
564 }
565 }
566
567 (HT::Concrete(a), HT::Abstract { shared, ty })
568 | (HT::Exact(a), HT::Abstract { shared, ty }) => {
569 let a_ty = &self.ty(a).composite_type;
570 if a_ty.shared != shared {
571 return false;
572 }
573 match ty {
574 Eq | Any => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
575 Struct => matches!(a_ty.inner, CT::Struct(_)),
576 Array => matches!(a_ty.inner, CT::Array(_)),
577 Func => matches!(a_ty.inner, CT::Func(_)),
578 _ => false,
579 }
580 }
581
582 (HT::Abstract { shared, ty }, HT::Concrete(b))
583 | (HT::Abstract { shared, ty }, HT::Exact(b)) => {
584 let b_ty = &self.ty(b).composite_type;
585 if shared != b_ty.shared {
586 return false;
587 }
588 match ty {
589 None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
590 NoFunc => matches!(b_ty.inner, CT::Func(_)),
591 _ => false,
592 }
593 }
594
595 (HT::Concrete(mut a), HT::Concrete(b)) | (HT::Exact(mut a), HT::Concrete(b)) => loop {
596 if a == b {
597 return true;
598 }
599 if let Some(supertype) = self.ty(a).supertype {
600 a = supertype;
601 } else {
602 return false;
603 }
604 },
605
606 (HT::Concrete(a), HT::Exact(b)) | (HT::Exact(a), HT::Exact(b)) => {
607 return a == b;
608 }
609 }
610 }
611
612 fn arbitrary_types(&mut self, u: &mut Unstructured) -> Result<()> {
613 assert!(self.config.min_types <= self.config.max_types);
614 while self.types.len() < self.config.min_types {
615 self.arbitrary_rec_group(u, AllowEmptyRecGroup::No)?;
616 }
617 while self.types.len() < self.config.max_types {
618 let keep_going = u.arbitrary().unwrap_or(false);
619 if !keep_going {
620 break;
621 }
622 self.arbitrary_rec_group(u, AllowEmptyRecGroup::Yes)?;
623 }
624 Ok(())
625 }
626
627 fn add_type(&mut self, ty: SubType) -> u32 {
628 let index = u32::try_from(self.types.len()).unwrap();
629
630 if let Some(supertype) = ty.supertype {
631 assert_eq!(self.is_shared_type(supertype), ty.composite_type.shared);
632 self.super_to_sub_types
633 .entry(supertype)
634 .or_default()
635 .push(index);
636 }
637
638 let list = match &ty.composite_type.inner {
639 CompositeInnerType::Array(_) => &mut self.array_types,
640 CompositeInnerType::Func(_) => &mut self.func_types,
641 CompositeInnerType::Struct(_) => &mut self.struct_types,
642 };
643 list.push(index);
644
645 const MAX_SUBTYPING_DEPTH: u32 = 60;
653 if !ty.is_final && ty.depth < MAX_SUBTYPING_DEPTH {
654 self.can_subtype.push(index);
655 }
656
657 self.types.push(ty);
658 index
659 }
660
661 fn arbitrary_rec_group(
662 &mut self,
663 u: &mut Unstructured,
664 kind: AllowEmptyRecGroup,
665 ) -> Result<()> {
666 let rec_group_start = self.types.len();
667
668 assert!(matches!(self.max_type_limit, MaxTypeLimit::ModuleTypes));
669
670 if self.config.gc_enabled {
671 if self.rec_groups.len() > 0 && u.ratio(1, u8::MAX)? {
673 return self.clone_rec_group(u, kind);
674 }
675
676 let max_rec_group_size = self.config.max_types - self.types.len();
678 let min_rec_group_size = match kind {
679 AllowEmptyRecGroup::Yes => 0,
680 AllowEmptyRecGroup::No => 1,
681 };
682 let rec_group_size = u.int_in_range(min_rec_group_size..=max_rec_group_size)?;
683 let type_ref_limit = u32::try_from(self.types.len() + rec_group_size).unwrap();
684 self.max_type_limit = MaxTypeLimit::Num(type_ref_limit);
685 for _ in 0..rec_group_size {
686 let ty = self.arbitrary_sub_type(u)?;
687 self.add_type(ty);
688 }
689 } else {
690 let type_ref_limit = u32::try_from(self.types.len()).unwrap();
691 self.max_type_limit = MaxTypeLimit::Num(type_ref_limit);
692 let ty = self.arbitrary_sub_type(u)?;
693 self.add_type(ty);
694 }
695
696 self.max_type_limit = MaxTypeLimit::ModuleTypes;
697
698 self.rec_groups.push(rec_group_start..self.types.len());
699 Ok(())
700 }
701
702 fn clone_rec_group(&mut self, u: &mut Unstructured, kind: AllowEmptyRecGroup) -> Result<()> {
703 let group = u.choose(&self.rec_groups)?.clone();
708 if group.is_empty() && kind == AllowEmptyRecGroup::No {
709 return Ok(());
710 }
711 if group.len() > self.config.max_types.saturating_sub(self.types.len()) {
712 return Ok(());
713 }
714
715 let new_rec_group_start = self.types.len();
723 for index in group {
724 let orig_ty_index = u32::try_from(index).unwrap();
725 let ty = self.ty(orig_ty_index).clone();
726 self.add_type(ty);
727 }
728 self.rec_groups.push(new_rec_group_start..self.types.len());
729 Ok(())
730 }
731
732 fn arbitrary_sub_type(&mut self, u: &mut Unstructured) -> Result<SubType> {
733 if !self.config.gc_enabled {
734 let shared = self.arbitrary_shared(u)?;
735 let func_type = self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?;
736 let composite_type = CompositeType {
737 inner: CompositeInnerType::Func(func_type),
738 shared,
739 descriptor: None,
740 describes: None,
741 };
742 return Ok(SubType {
743 is_final: true,
744 supertype: None,
745 composite_type,
746 depth: 1,
747 });
748 }
749
750 if !self.can_subtype.is_empty() && u.ratio(1, 32_u8)? {
751 self.arbitrary_sub_type_of_super_type(u)
752 } else {
753 Ok(SubType {
754 is_final: u.arbitrary()?,
755 supertype: None,
756 composite_type: self.arbitrary_composite_type(u)?,
757 depth: 1,
758 })
759 }
760 }
761
762 fn arbitrary_sub_type_of_super_type(&mut self, u: &mut Unstructured) -> Result<SubType> {
763 let supertype = *u.choose(&self.can_subtype)?;
764 let mut composite_type = self.types[usize::try_from(supertype).unwrap()]
765 .composite_type
766 .clone();
767 match &mut composite_type.inner {
768 CompositeInnerType::Array(a) => {
769 a.0 = self.arbitrary_matching_field_type(u, a.0)?;
770 }
771 CompositeInnerType::Func(f) => {
772 *f = self.arbitrary_matching_func_type(u, f)?;
773 }
774 CompositeInnerType::Struct(s) => {
775 *s = self.propagate_shared(composite_type.shared, |m| {
776 m.arbitrary_matching_struct_type(u, s)
777 })?;
778 }
779 }
780 Ok(SubType {
781 is_final: u.arbitrary()?,
782 supertype: Some(supertype),
783 composite_type,
784 depth: 1 + self.types[supertype as usize].depth,
785 })
786 }
787
788 fn arbitrary_matching_struct_type(
789 &mut self,
790 u: &mut Unstructured,
791 ty: &StructType,
792 ) -> Result<StructType> {
793 let len_extra_fields = u.int_in_range(0..=5)?;
794 let mut fields = Vec::with_capacity(ty.fields.len() + len_extra_fields);
795 for field in ty.fields.iter() {
796 fields.push(self.arbitrary_matching_field_type(u, *field)?);
797 }
798 for _ in 0..len_extra_fields {
799 fields.push(self.arbitrary_field_type(u)?);
800 }
801 Ok(StructType {
802 fields: fields.into_boxed_slice(),
803 })
804 }
805
806 fn arbitrary_matching_field_type(
807 &mut self,
808 u: &mut Unstructured,
809 ty: FieldType,
810 ) -> Result<FieldType> {
811 if ty.mutable {
812 Ok(ty)
813 } else {
814 Ok(FieldType {
815 element_type: self.arbitrary_matching_storage_type(u, ty.element_type)?,
816 mutable: false,
817 })
818 }
819 }
820
821 fn arbitrary_matching_storage_type(
822 &mut self,
823 u: &mut Unstructured,
824 ty: StorageType,
825 ) -> Result<StorageType> {
826 match ty {
827 StorageType::I8 => Ok(StorageType::I8),
828 StorageType::I16 => Ok(StorageType::I16),
829 StorageType::Val(ty) => Ok(StorageType::Val(self.arbitrary_matching_val_type(u, ty)?)),
830 }
831 }
832
833 fn arbitrary_matching_val_type(
834 &mut self,
835 u: &mut Unstructured,
836 ty: ValType,
837 ) -> Result<ValType> {
838 match ty {
839 ValType::I32 => Ok(ValType::I32),
840 ValType::I64 => Ok(ValType::I64),
841 ValType::F32 => Ok(ValType::F32),
842 ValType::F64 => Ok(ValType::F64),
843 ValType::V128 => Ok(ValType::V128),
844 ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_matching_ref_type(u, ty)?)),
845 }
846 }
847
848 fn arbitrary_matching_ref_type(&self, u: &mut Unstructured, ty: RefType) -> Result<RefType> {
849 Ok(RefType {
850 nullable: ty.nullable,
851 heap_type: self.arbitrary_matching_heap_type(u, ty.heap_type)?,
852 })
853 }
854
855 fn arbitrary_matching_heap_type(&self, u: &mut Unstructured, ty: HeapType) -> Result<HeapType> {
856 use {AbstractHeapType as AHT, CompositeInnerType as CT, HeapType as HT};
857
858 if !self.config.gc_enabled {
859 return Ok(ty);
860 }
861
862 let mut choices = vec![ty];
863 match ty {
864 HT::Abstract { shared, ty } => {
865 use AbstractHeapType::*;
866 let add_abstract = |choices: &mut Vec<HT>, tys: &[AHT]| {
867 choices.extend(tys.iter().map(|&ty| HT::Abstract { shared, ty }));
868 };
869 let add_concrete = |choices: &mut Vec<HT>, tys: &[u32]| {
870 choices.extend(
871 tys.iter()
872 .filter(|&&idx| shared == self.is_shared_type(idx))
873 .copied()
874 .map(HT::Concrete),
875 );
876 };
877 match ty {
878 Any => {
879 add_abstract(&mut choices, &[Eq, Struct, Array, I31, None]);
880 add_concrete(&mut choices, &self.array_types);
881 add_concrete(&mut choices, &self.struct_types);
882 }
883 Eq => {
884 add_abstract(&mut choices, &[Struct, Array, I31, None]);
885 add_concrete(&mut choices, &self.array_types);
886 add_concrete(&mut choices, &self.struct_types);
887 }
888 Struct => {
889 add_abstract(&mut choices, &[Struct, None]);
890 add_concrete(&mut choices, &self.struct_types);
891 }
892 Array => {
893 add_abstract(&mut choices, &[Array, None]);
894 add_concrete(&mut choices, &self.array_types);
895 }
896 I31 => {
897 add_abstract(&mut choices, &[None]);
898 }
899 Func => {
900 add_abstract(&mut choices, &[NoFunc]);
901 add_concrete(&mut choices, &self.func_types);
902 }
903 Extern => {
904 add_abstract(&mut choices, &[NoExtern]);
905 }
906 Exn | NoExn | None | NoExtern | NoFunc | Cont | NoCont => {}
907 }
908 }
909 HT::Concrete(idx) => {
910 if let Some(subs) = self.super_to_sub_types.get(&idx) {
911 choices.extend(subs.iter().copied().map(HT::Concrete));
912 }
913 if self.config.custom_descriptors_enabled {
914 choices.push(HT::Exact(idx));
915 if let Some(subs) = self.super_to_sub_types.get(&idx) {
916 choices.extend(subs.iter().copied().map(HT::Concrete));
917 }
918 }
919 match self
920 .types
921 .get(usize::try_from(idx).unwrap())
922 .map(|ty| (ty.composite_type.shared, &ty.composite_type.inner))
923 {
924 Some((shared, CT::Array(_) | CT::Struct(_))) => choices.push(HT::Abstract {
925 shared,
926 ty: AbstractHeapType::None,
927 }),
928 Some((shared, CT::Func(_))) => choices.push(HT::Abstract {
929 shared,
930 ty: AbstractHeapType::NoFunc,
931 }),
932 None => {
933 }
939 }
940 }
941 HT::Exact(_) => (),
942 }
943 Ok(*u.choose(&choices)?)
944 }
945
946 fn arbitrary_matching_func_type(
947 &mut self,
948 u: &mut Unstructured,
949 ty: &FuncType,
950 ) -> Result<Rc<FuncType>> {
951 let mut params = Vec::with_capacity(ty.params.len());
955 for param in &ty.params {
956 params.push(self.arbitrary_super_type_of_val_type(u, *param)?);
957 }
958 let mut results = Vec::with_capacity(ty.results.len());
959 for result in &ty.results {
960 results.push(self.arbitrary_matching_val_type(u, *result)?);
961 }
962 Ok(Rc::new(FuncType { params, results }))
963 }
964
965 fn arbitrary_super_type_of_val_type(
966 &mut self,
967 u: &mut Unstructured,
968 ty: ValType,
969 ) -> Result<ValType> {
970 match ty {
971 ValType::I32 => Ok(ValType::I32),
972 ValType::I64 => Ok(ValType::I64),
973 ValType::F32 => Ok(ValType::F32),
974 ValType::F64 => Ok(ValType::F64),
975 ValType::V128 => Ok(ValType::V128),
976 ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_super_type_of_ref_type(u, ty)?)),
977 }
978 }
979
980 fn arbitrary_super_type_of_ref_type(
981 &self,
982 u: &mut Unstructured,
983 ty: RefType,
984 ) -> Result<RefType> {
985 Ok(RefType {
986 nullable: true,
993 heap_type: self.arbitrary_super_type_of_heap_type(u, ty.heap_type)?,
994 })
995 }
996
997 fn arbitrary_super_type_of_heap_type(
998 &self,
999 u: &mut Unstructured,
1000 ty: HeapType,
1001 ) -> Result<HeapType> {
1002 use {AbstractHeapType as AHT, CompositeInnerType as CT, HeapType as HT};
1003
1004 if !self.config.gc_enabled {
1005 return Ok(ty);
1006 }
1007
1008 let mut choices = vec![ty];
1009 match ty {
1010 HT::Abstract { shared, ty } => {
1011 use AbstractHeapType::*;
1012 let add_abstract = |choices: &mut Vec<HT>, tys: &[AHT]| {
1013 choices.extend(tys.iter().map(|&ty| HT::Abstract { shared, ty }));
1014 };
1015 let add_concrete = |choices: &mut Vec<HT>, tys: &[u32]| {
1016 choices.extend(
1017 tys.iter()
1018 .filter(|&&idx| shared == self.is_shared_type(idx))
1019 .copied()
1020 .map(HT::Concrete),
1021 );
1022 };
1023 match ty {
1024 None => {
1025 add_abstract(&mut choices, &[Any, Eq, Struct, Array, I31]);
1026 add_concrete(&mut choices, &self.array_types);
1027 add_concrete(&mut choices, &self.struct_types);
1028 }
1029 NoExtern => {
1030 add_abstract(&mut choices, &[Extern]);
1031 }
1032 NoFunc => {
1033 add_abstract(&mut choices, &[Func]);
1034 add_concrete(&mut choices, &self.func_types);
1035 }
1036 NoExn => {
1037 add_abstract(&mut choices, &[Exn]);
1038 }
1039 Struct | Array | I31 => {
1040 add_abstract(&mut choices, &[Any, Eq]);
1041 }
1042 Eq => {
1043 add_abstract(&mut choices, &[Any]);
1044 }
1045 NoCont => {
1046 add_abstract(&mut choices, &[Cont]);
1047 }
1048 Exn | Any | Func | Extern | Cont => {}
1049 }
1050 }
1051 HT::Concrete(mut idx) => {
1052 if let Some(sub_ty) = &self.types.get(usize::try_from(idx).unwrap()) {
1053 use AbstractHeapType::*;
1054 let ht = |ty| HT::Abstract {
1055 shared: sub_ty.composite_type.shared,
1056 ty,
1057 };
1058 match &sub_ty.composite_type.inner {
1059 CT::Array(_) => {
1060 choices.extend([ht(Any), ht(Eq), ht(Array)]);
1061 }
1062 CT::Func(_) => {
1063 choices.push(ht(Func));
1064 }
1065 CT::Struct(_) => {
1066 choices.extend([ht(Any), ht(Eq), ht(Struct)]);
1067 }
1068 }
1069 } else {
1070 }
1077 while let Some(supertype) = self
1078 .types
1079 .get(usize::try_from(idx).unwrap())
1080 .and_then(|ty| ty.supertype)
1081 {
1082 choices.push(HT::Concrete(supertype));
1083 idx = supertype;
1084 }
1085 }
1086 HT::Exact(_) => (),
1087 }
1088 Ok(*u.choose(&choices)?)
1089 }
1090
1091 fn arbitrary_composite_type(&mut self, u: &mut Unstructured) -> Result<CompositeType> {
1092 use CompositeInnerType as CT;
1093 let shared = self.arbitrary_shared(u)?;
1094
1095 if !self.config.gc_enabled {
1096 return Ok(CompositeType {
1097 shared,
1098 inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?),
1099 descriptor: None,
1100 describes: None,
1101 });
1102 }
1103
1104 match u.int_in_range(0..=2)? {
1105 0 => Ok(CompositeType {
1106 shared,
1107 inner: CT::Array(ArrayType(
1108 self.propagate_shared(shared, |m| m.arbitrary_field_type(u))?,
1109 )),
1110 descriptor: None,
1111 describes: None,
1112 }),
1113 1 => Ok(CompositeType {
1114 shared,
1115 inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?),
1116 descriptor: None,
1117 describes: None,
1118 }),
1119 2 => Ok(CompositeType {
1120 shared,
1121 inner: CT::Struct(self.propagate_shared(shared, |m| m.arbitrary_struct_type(u))?),
1122 descriptor: None, describes: None,
1124 }),
1125 _ => unreachable!(),
1126 }
1127 }
1128
1129 fn arbitrary_struct_type(&mut self, u: &mut Unstructured) -> Result<StructType> {
1130 let len = u.int_in_range(0..=20)?;
1131 let mut fields = Vec::with_capacity(len);
1132 for _ in 0..len {
1133 fields.push(self.arbitrary_field_type(u)?);
1134 }
1135 Ok(StructType {
1136 fields: fields.into_boxed_slice(),
1137 })
1138 }
1139
1140 fn arbitrary_field_type(&mut self, u: &mut Unstructured) -> Result<FieldType> {
1141 Ok(FieldType {
1142 element_type: self.arbitrary_storage_type(u)?,
1143 mutable: u.arbitrary()?,
1144 })
1145 }
1146
1147 fn arbitrary_storage_type(&mut self, u: &mut Unstructured) -> Result<StorageType> {
1148 match u.int_in_range(0..=2)? {
1149 0 => Ok(StorageType::I8),
1150 1 => Ok(StorageType::I16),
1151 2 => Ok(StorageType::Val(self.arbitrary_valtype(u)?)),
1152 _ => unreachable!(),
1153 }
1154 }
1155
1156 fn arbitrary_ref_type(&self, u: &mut Unstructured) -> Result<RefType> {
1157 if !self.config.reference_types_enabled {
1158 return Ok(RefType::FUNCREF);
1159 }
1160 Ok(RefType {
1161 nullable: true,
1162 heap_type: self.arbitrary_heap_type(u)?,
1163 })
1164 }
1165
1166 fn arbitrary_heap_type(&self, u: &mut Unstructured) -> Result<HeapType> {
1167 assert!(self.config.reference_types_enabled);
1168
1169 let concrete_type_limit = match self.max_type_limit {
1170 MaxTypeLimit::Num(n) => n,
1171 MaxTypeLimit::ModuleTypes => u32::try_from(self.types.len()).unwrap(),
1172 };
1173
1174 if self.config.gc_enabled && concrete_type_limit > 0 && u.arbitrary()? {
1175 let idx = u.int_in_range(0..=concrete_type_limit - 1)?;
1176 if let Some(ty) = self.types.get(idx as usize) {
1182 if !(self.must_share && !ty.composite_type.shared) {
1185 return Ok(HeapType::Concrete(idx));
1186 }
1187 }
1188 }
1189
1190 use AbstractHeapType::*;
1191 let mut choices = vec![Func, Extern];
1192 if self.config.exceptions_enabled {
1193 choices.push(Exn);
1194 }
1195 if self.config.gc_enabled {
1196 choices.extend(
1197 [Any, None, NoExtern, NoFunc, Eq, Struct, Array, I31]
1198 .iter()
1199 .copied(),
1200 );
1201 }
1202
1203 Ok(HeapType::Abstract {
1204 shared: self.arbitrary_shared(u)?,
1205 ty: *u.choose(&choices)?,
1206 })
1207 }
1208
1209 fn arbitrary_func_type(&mut self, u: &mut Unstructured) -> Result<Rc<FuncType>> {
1210 let mut params = vec![];
1211 let mut results = vec![];
1212 let max_params = 20;
1213 arbitrary_loop(u, 0, max_params, |u| {
1214 params.push(self.arbitrary_valtype(u)?);
1215 Ok(true)
1216 })?;
1217 let max_results = if self.config.multi_value_enabled {
1218 max_params
1219 } else {
1220 1
1221 };
1222 arbitrary_loop(u, 0, max_results, |u| {
1223 results.push(self.arbitrary_valtype(u)?);
1224 Ok(true)
1225 })?;
1226 Ok(Rc::new(FuncType { params, results }))
1227 }
1228
1229 fn can_add_local_or_import_tag(&self) -> bool {
1230 self.config.exceptions_enabled
1231 && self.has_tag_func_types()
1232 && self.tags.len() < self.config.max_tags
1233 }
1234
1235 fn can_add_local_or_import_func(&self) -> bool {
1236 !self.func_types.is_empty() && self.funcs.len() < self.config.max_funcs
1237 }
1238
1239 fn can_add_local_or_import_table(&self) -> bool {
1240 self.tables.len() < self.config.max_tables
1241 }
1242
1243 fn can_add_local_or_import_global(&self) -> bool {
1244 self.globals.len() < self.config.max_globals
1245 }
1246
1247 fn can_add_local_or_import_memory(&self) -> bool {
1248 self.memories.len() < self.config.max_memories
1249 }
1250
1251 fn imports_exports_from_module_shape(&mut self, u: &mut Unstructured) -> Result<bool> {
1252 let example_module = if let Some(wasm) = self.config.module_shape.clone() {
1253 wasm
1254 } else {
1255 return Ok(false);
1256 };
1257
1258 #[cfg(feature = "wasmparser")]
1259 {
1260 self._imports_exports_from_module_shape(u, &example_module)?;
1261 Ok(true)
1262 }
1263 #[cfg(not(feature = "wasmparser"))]
1264 {
1265 let _ = (example_module, u);
1266 panic!("support for `module_shape` was disabled at compile time");
1267 }
1268 }
1269
1270 #[cfg(feature = "wasmparser")]
1271 fn _imports_exports_from_module_shape(
1272 &mut self,
1273 u: &mut Unstructured,
1274 example_module: &[u8],
1275 ) -> Result<()> {
1276 let mut available_funcs: Vec<u32> = Vec::new();
1280 let mut available_tags: Vec<wasmparser::TagType> = Vec::new();
1281 let mut available_tables: Vec<wasmparser::TableType> = Vec::new();
1282 let mut available_globals: Vec<wasmparser::GlobalType> = Vec::new();
1283 let mut available_memories: Vec<wasmparser::MemoryType> = Vec::new();
1284
1285 let mut required_types: Vec<SubType> = Vec::new();
1286 let mut required_recgrps: Vec<usize> = Vec::new();
1287 let mut required_imports: Vec<wasmparser::Imports> = Vec::new();
1288 let mut required_exports: Vec<wasmparser::Export> = Vec::new();
1289 let mut validator = wasmparser::Validator::new();
1290 validator
1291 .validate_all(example_module)
1292 .expect("Failed to validate `module_shape` module");
1293 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
1294 match payload.expect("could not parse the `module_shape` module") {
1295 wasmparser::Payload::TypeSection(type_reader) => {
1296 for recgrp in type_reader {
1297 let recgrp = recgrp.expect("could not read recursive group");
1298 required_recgrps.push(recgrp.types().len());
1299 for subtype in recgrp.into_types() {
1300 let mut subtype: SubType = subtype.try_into().unwrap();
1301 if let Some(supertype_idx) = subtype.supertype {
1302 subtype.depth = required_types[supertype_idx as usize].depth + 1;
1303 }
1304 required_types.push(subtype);
1305 }
1306 }
1307 }
1308 wasmparser::Payload::ImportSection(import_reader) => {
1309 for imports in import_reader {
1310 required_imports.push(imports.expect("could not read imports"));
1311 }
1312 }
1313 wasmparser::Payload::ExportSection(export_reader) => {
1314 for ex in export_reader {
1315 let ex = ex.expect("could not read export");
1316 required_exports.push(ex);
1317 }
1318 }
1319 wasmparser::Payload::FunctionSection(function_reader) => {
1320 for func in function_reader {
1321 let func = func.expect("could not read function");
1322 available_funcs.push(func);
1323 }
1324 }
1325 wasmparser::Payload::TagSection(tag_reader) => {
1326 for tag in tag_reader {
1327 let tag = tag.expect("could not read tag");
1328 available_tags.push(tag);
1329 }
1330 }
1331 wasmparser::Payload::TableSection(table_reader) => {
1332 for table in table_reader {
1333 let table = table.expect("could not read table");
1334 available_tables.push(table.ty);
1335 }
1336 }
1337 wasmparser::Payload::MemorySection(memory_reader) => {
1338 for memory in memory_reader {
1339 let memory = memory.expect("could not read memory");
1340 available_memories.push(memory);
1341 }
1342 }
1343 wasmparser::Payload::GlobalSection(global_reader) => {
1344 for global in global_reader {
1345 let global = global.expect("could not read global");
1346 available_globals.push(global.ty);
1347 }
1348 }
1349 _ => {}
1350 }
1351 }
1352
1353 let mut recgrp_start_idx = self.types.len();
1356 for size in required_recgrps {
1357 self.rec_groups
1358 .push(recgrp_start_idx..recgrp_start_idx + size);
1359 recgrp_start_idx += size;
1360 }
1361 for ty in &required_types {
1362 self.add_type(ty.clone());
1363 }
1364
1365 let mut imported_funcs: Vec<u32> = Vec::new();
1369 let mut imported_tags: Vec<wasmparser::TagType> = Vec::new();
1370 let mut imported_tables: Vec<wasmparser::TableType> = Vec::new();
1371 let mut imported_globals: Vec<wasmparser::GlobalType> = Vec::new();
1372 let mut imported_memories: Vec<wasmparser::MemoryType> = Vec::new();
1373 fn entity_type(ty: wasmparser::TypeRef, required_types: &[SubType]) -> EntityType {
1374 match ty {
1375 wasmparser::TypeRef::Func(sig_idx) => {
1376 let ty = required_types
1377 .get(sig_idx as usize)
1378 .expect("signature index refers to a type out of bounds");
1379 EntityType::Func(sig_idx, Rc::clone(ty.composite_type.unwrap_func()))
1380 }
1381 wasmparser::TypeRef::FuncExact(_) => panic!("Unexpected func_exact import"),
1382 wasmparser::TypeRef::Tag(ty) => {
1383 let func_type = required_types
1384 .get(ty.func_type_idx as usize)
1385 .expect("function type index for tag refers to a type out of bounds")
1386 .composite_type
1387 .unwrap_func();
1388 EntityType::Tag(TagType {
1389 func_type_idx: ty.func_type_idx,
1390 func_type: Rc::clone(func_type),
1391 })
1392 }
1393 wasmparser::TypeRef::Table(ty) => EntityType::Table(ty.try_into().unwrap()),
1394 wasmparser::TypeRef::Memory(ty) => EntityType::Memory(ty.into()),
1395 wasmparser::TypeRef::Global(ty) => EntityType::Global(ty.try_into().unwrap()),
1396 }
1397 }
1398 let mut translate_import = |import: wasmparser::Import| {
1399 let parser_ty = import.ty;
1400 let ty = entity_type(parser_ty, &required_types);
1401 match (parser_ty, &ty) {
1402 (wasmparser::TypeRef::Func(sig_idx), EntityType::Func(_, func_type)) => {
1403 imported_funcs.push(sig_idx);
1404 self.funcs.push((sig_idx, Rc::clone(func_type)));
1405 }
1406 (wasmparser::TypeRef::Tag(parser_ty), EntityType::Tag(tag_type)) => {
1407 imported_tags.push(parser_ty);
1408 self.tags.push(tag_type.clone());
1409 }
1410 (wasmparser::TypeRef::Table(parser_ty), EntityType::Table(ty)) => {
1411 imported_tables.push(parser_ty);
1412 self.tables.push(*ty);
1413 }
1414 (wasmparser::TypeRef::Memory(parser_ty), EntityType::Memory(ty)) => {
1415 imported_memories.push(parser_ty);
1416 self.memories.push(*ty);
1417 }
1418 (wasmparser::TypeRef::Global(parser_ty), EntityType::Global(ty)) => {
1419 imported_globals.push(parser_ty);
1420 self.globals.push(*ty);
1421 }
1422 _ => unreachable!(),
1423 }
1424 self.num_imports += 1;
1425 Import {
1426 module: import.module.to_string(),
1427 name: import.name.to_string(),
1428 entity_type: ty,
1429 }
1430 };
1431
1432 for imports in required_imports {
1433 match imports {
1434 wasmparser::Imports::Single(_, import) => {
1435 self.imports.push(Imports::Single(translate_import(import)));
1436 }
1437 wasmparser::Imports::Compact1 { module, items } => {
1438 let items = items
1439 .into_iter()
1440 .map(|item| {
1441 let item = item.expect("could not read compact import");
1442 translate_import(wasmparser::Import {
1443 module,
1444 name: item.name,
1445 ty: item.ty,
1446 })
1447 })
1448 .collect::<Vec<_>>();
1449 if self.config.compact_imports_enabled {
1450 if !items.is_empty() {
1451 self.imports.push(Imports::Compact1 {
1452 module: module.to_string(),
1453 items,
1454 });
1455 }
1456 } else {
1457 self.imports.extend(items.into_iter().map(Imports::Single));
1458 }
1459 }
1460 wasmparser::Imports::Compact2 { module, ty, names } => {
1461 let items = names
1462 .into_iter()
1463 .map(|name| {
1464 translate_import(wasmparser::Import {
1465 module,
1466 name: name.expect("could not read compact import name"),
1467 ty,
1468 })
1469 })
1470 .collect::<Vec<_>>();
1471 if self.config.compact_imports_enabled {
1472 if !items.is_empty() {
1473 self.imports.push(Imports::Compact2 {
1474 module: module.to_string(),
1475 entity_type: entity_type(ty, &required_types),
1476 names: items.into_iter().map(|item| item.name).collect(),
1477 });
1478 }
1479 } else {
1480 self.imports.extend(items.into_iter().map(Imports::Single));
1481 }
1482 }
1483 }
1484 }
1485 available_tags.splice(0..0, imported_tags);
1486 available_funcs.splice(0..0, imported_funcs);
1487 available_tables.splice(0..0, imported_tables);
1488 available_globals.splice(0..0, imported_globals);
1489 available_memories.splice(0..0, imported_memories);
1490
1491 for export in required_exports {
1493 let index = match export.kind {
1494 wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {
1495 match available_funcs.get(export.index as usize) {
1496 None => panic!("function index out of bounds"),
1497 Some(sig_idx) => match required_types.get(*sig_idx as usize) {
1498 None => panic!("signature index refers to a type out of bounds"),
1499 Some(ty) => match &ty.composite_type.inner {
1500 CompositeInnerType::Func(func_type) => {
1501 let func_index = self.funcs.len() as u32;
1502 self.funcs.push((*sig_idx, Rc::clone(func_type)));
1503 self.num_defined_funcs += 1;
1504 func_index
1505 }
1506 _ => panic!("a function type is required for function export"),
1507 },
1508 },
1509 }
1510 }
1511
1512 wasmparser::ExternalKind::Tag => match available_tags.get(export.index as usize) {
1513 None => panic!("tag index out of bounds"),
1514 Some(wasmparser::TagType { func_type_idx, .. }) => {
1515 match required_types.get(*func_type_idx as usize) {
1516 None => {
1517 panic!("function type index for tag refers to a type out of bounds")
1518 }
1519 Some(ty) => match &ty.composite_type.inner {
1520 CompositeInnerType::Func(func_type) => {
1521 let tag_index = self.tags.len() as u32;
1522 self.tags.push(TagType {
1523 func_type_idx: *func_type_idx,
1524 func_type: Rc::clone(func_type),
1525 });
1526 self.num_defined_tags += 1;
1527 tag_index
1528 }
1529 _ => panic!("a function type is required for tag export"),
1530 },
1531 }
1532 }
1533 },
1534
1535 wasmparser::ExternalKind::Table => {
1536 match available_tables.get(export.index as usize) {
1537 None => panic!("table index out of bounds"),
1538 Some(ty) => {
1539 self.add_arbitrary_table_of_type((*ty).try_into().unwrap(), u)?
1540 }
1541 }
1542 }
1543
1544 wasmparser::ExternalKind::Memory => {
1545 match available_memories.get(export.index as usize) {
1546 None => panic!("memory index out of bounds"),
1547 Some(ty) => self.add_arbitrary_memory_of_type((*ty).into())?,
1548 }
1549 }
1550
1551 wasmparser::ExternalKind::Global => {
1552 match available_globals.get(export.index as usize) {
1553 None => panic!("global index out of bounds"),
1554 Some(ty) => {
1555 self.add_arbitrary_global_of_type((*ty).try_into().unwrap(), u)?
1556 }
1557 }
1558 }
1559 };
1560 self.exports
1561 .push((export.name.to_string(), export.kind.into(), index));
1562 self.export_names.insert(export.name.to_string());
1563 }
1564
1565 Ok(())
1566 }
1567
1568 fn arbitrary_imports(&mut self, u: &mut Unstructured) -> Result<()> {
1569 if self.num_imports > self.config.max_imports || self.type_size > self.config.max_type_size
1570 {
1571 return Err(arbitrary::Error::IncorrectFormat);
1572 }
1573
1574 let mut import_names = HashSet::new();
1575 let mut entity_generation_failed = false;
1576 while !entity_generation_failed && self.num_imports < self.config.max_imports {
1577 let reached_min_imports = self.num_imports >= self.config.min_imports;
1578 if reached_min_imports {
1579 let keep_going = u.arbitrary().unwrap_or(false);
1580 if !keep_going {
1581 break;
1582 }
1583 }
1584
1585 let import_kind = self.arbitrary_import_group_kind(u)?;
1586 let module = limited_string(1_000, u)?;
1587 match import_kind {
1588 ImportsKind::Single => {
1589 let Some(entity_type) = self.arbitrary_import_entity_type(u)? else {
1590 break;
1591 };
1592 let name = self.arbitrary_import_name(&module, &mut import_names, u)?;
1593 self.commit_entity_type(&entity_type);
1594 self.imports.push(Imports::Single(Import {
1595 module,
1596 name,
1597 entity_type,
1598 }));
1599 }
1600 ImportsKind::Compact1 => {
1601 let mut items = Vec::new();
1602 while self.num_imports < self.config.max_imports {
1603 let keep_going = u.arbitrary().unwrap_or(false);
1604 if !keep_going {
1605 break;
1606 }
1607
1608 let Some(entity_type) = self.arbitrary_import_entity_type(u)? else {
1609 entity_generation_failed = true;
1612 break;
1613 };
1614 let name = self.arbitrary_import_name(&module, &mut import_names, u)?;
1615 self.commit_entity_type(&entity_type);
1616 items.push(Import {
1617 module: module.clone(),
1618 name,
1619 entity_type,
1620 });
1621 }
1622 if !items.is_empty() {
1623 self.imports.push(Imports::Compact1 { module, items });
1624 }
1625 }
1626 ImportsKind::Compact2 => {
1627 let Some(entity_type) = self.arbitrary_import_entity_type(u)? else {
1628 break;
1629 };
1630
1631 let mut names = Vec::new();
1632 while self.num_imports < self.config.max_imports {
1633 let keep_going = u.arbitrary().unwrap_or(false);
1634 if !keep_going {
1635 break;
1636 }
1637
1638 let remaining_type_size = self.config.max_type_size - self.type_size;
1639 let import_type_size = entity_type.size() + 1;
1640 if import_type_size > remaining_type_size
1641 || !self.can_push_entity_type(&entity_type)
1642 {
1643 entity_generation_failed = true;
1644 break;
1645 }
1646
1647 let name = self.arbitrary_import_name(&module, &mut import_names, u)?;
1648 self.commit_entity_type(&entity_type);
1649 names.push(name);
1650 }
1651
1652 if !names.is_empty() {
1653 self.imports.push(Imports::Compact2 {
1654 module,
1655 entity_type,
1656 names,
1657 });
1658 }
1659 }
1660 }
1661 }
1662
1663 if self.num_imports < self.config.min_imports {
1664 Err(arbitrary::Error::IncorrectFormat)
1665 } else {
1666 Ok(())
1667 }
1668 }
1669
1670 fn arbitrary_import_group_kind(&self, u: &mut Unstructured) -> Result<ImportsKind> {
1671 if self.config.compact_imports_enabled {
1672 u.arbitrary()
1673 } else {
1674 Ok(ImportsKind::Single)
1675 }
1676 }
1677
1678 fn arbitrary_import_entity_type(&mut self, u: &mut Unstructured) -> Result<Option<EntityType>> {
1686 type GenerateEntity = fn(&mut Unstructured, &mut Module) -> Result<EntityType>;
1688
1689 let mut choices: Vec<GenerateEntity> = Vec::new();
1690 if self.can_add_local_or_import_tag() {
1691 choices.push(|u, module| Ok(EntityType::Tag(module.arbitrary_tag_type(u)?)));
1692 }
1693 if self.can_add_local_or_import_func() {
1694 choices.push(|u, module| {
1695 let idx = *u.choose(&module.func_types)?;
1696 Ok(EntityType::Func(idx, Rc::clone(module.func_type(idx))))
1697 });
1698 }
1699 if self.can_add_local_or_import_global() {
1700 choices.push(|u, module| Ok(EntityType::Global(module.arbitrary_global_type(u)?)));
1701 }
1702 if self.can_add_local_or_import_memory() {
1703 choices
1704 .push(|u, module| Ok(EntityType::Memory(arbitrary_memtype(u, module.config())?)));
1705 }
1706 if self.can_add_local_or_import_table() {
1707 choices.push(|u, module| {
1708 Ok(EntityType::Table(arbitrary_table_type(
1709 u,
1710 module.config(),
1711 Some(module),
1712 )?))
1713 });
1714 }
1715
1716 if choices.is_empty() {
1717 return Ok(None);
1718 }
1719 let generate = *u.choose(&choices)?;
1720 let entity_type = generate(u, self)?;
1721
1722 let remaining_type_size = self.config.max_type_size - self.type_size;
1724 let import_type_size = entity_type.size() + 1;
1725 Ok((import_type_size <= remaining_type_size).then_some(entity_type))
1726 }
1727
1728 fn arbitrary_import_name(
1729 &self,
1730 module: &str,
1731 import_names: &mut HashSet<(String, String)>,
1732 u: &mut Unstructured,
1733 ) -> Result<String> {
1734 let mut import = (module.to_owned(), limited_string(1_000, u)?);
1735 match self.duplicate_imports_behavior {
1736 DuplicateImportsBehavior::Allowed => Ok(import.1),
1737 DuplicateImportsBehavior::Disallowed => {
1738 while import_names.contains(&import) {
1739 use std::fmt::Write;
1740 write!(&mut import.1, "{}", import_names.len()).unwrap();
1741 }
1742 import_names.insert(import.clone());
1743 Ok(import.1)
1744 }
1745 }
1746 }
1747
1748 fn can_push_entity_type(&self, entity_type: &EntityType) -> bool {
1750 match entity_type {
1751 EntityType::Tag(_) => self.tags.len() < self.config.max_tags,
1752 EntityType::Func(_, _) => self.funcs.len() < self.config.max_funcs,
1753 EntityType::Global(_) => self.globals.len() < self.config.max_globals,
1754 EntityType::Table(_) => self.tables.len() < self.config.max_tables,
1755 EntityType::Memory(_) => self.memories.len() < self.config.max_memories,
1756 }
1757 }
1758
1759 fn commit_entity_type(&mut self, entity_type: &EntityType) {
1761 self.type_size += entity_type.size() + 1;
1762 match entity_type {
1763 EntityType::Tag(ty) => self.tags.push(ty.clone()),
1764 EntityType::Func(idx, ty) => self.funcs.push((*idx, Rc::clone(ty))),
1765 EntityType::Global(ty) => self.globals.push(*ty),
1766 EntityType::Table(ty) => self.tables.push(*ty),
1767 EntityType::Memory(ty) => self.memories.push(*ty),
1768 }
1769 self.num_imports += 1;
1770 }
1771
1772 fn arbitrary_imports_from_available(&mut self, u: &mut Unstructured) -> Result<bool> {
1778 let example_module = if let Some(wasm) = self.config.available_imports.take() {
1779 wasm
1780 } else {
1781 return Ok(false);
1782 };
1783
1784 #[cfg(feature = "wasmparser")]
1785 {
1786 self._arbitrary_imports_from_available(u, &example_module)?;
1787 Ok(true)
1788 }
1789 #[cfg(not(feature = "wasmparser"))]
1790 {
1791 let _ = (example_module, u);
1792 panic!("support for `available_imports` was disabled at compile time");
1793 }
1794 }
1795
1796 #[cfg(feature = "wasmparser")]
1797 fn _arbitrary_imports_from_available(
1798 &mut self,
1799 u: &mut Unstructured,
1800 example_module: &[u8],
1801 ) -> Result<()> {
1802 let mut new_recgrps = Vec::<usize>::new();
1809 let mut available_types = Vec::<SubType>::new();
1810 let mut available_imports = Vec::<wasmparser::Import>::new();
1811 let mut validator = wasmparser::Validator::new();
1812 validator
1813 .validate_all(example_module)
1814 .expect("Failed to validate `module_shape` module");
1815 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
1816 match payload.expect("could not parse the available import payload") {
1817 wasmparser::Payload::TypeSection(type_reader) => {
1818 for recgrp in type_reader {
1819 let recgrp = recgrp.expect("could not read recursive group");
1820 new_recgrps.push(recgrp.types().len());
1821 for subtype in recgrp.into_types() {
1822 let mut subtype: SubType = subtype.try_into().unwrap();
1823 if let Some(supertype_idx) = subtype.supertype {
1824 subtype.depth = available_types[supertype_idx as usize].depth + 1;
1825 }
1826 available_types.push(subtype);
1827 }
1828 }
1829 }
1830 wasmparser::Payload::ImportSection(import_reader) => {
1831 for im in import_reader.into_imports() {
1832 let im = im.expect("could not read import");
1833 let use_import = u.arbitrary().unwrap_or(false);
1836 if !use_import {
1837 continue;
1838 }
1839 available_imports.push(im);
1840 }
1841 }
1842 _ => {}
1843 }
1844 }
1845
1846 let mut new_imports = Vec::with_capacity(available_imports.len());
1851 for import in available_imports {
1852 let type_size_budget = self.config.max_type_size - self.type_size;
1853 let entity_type = match &import.ty {
1854 wasmparser::TypeRef::Func(sig_idx) => {
1855 if self.funcs.len() >= self.config.max_funcs {
1856 continue;
1857 } else {
1858 match available_types.get(*sig_idx as usize) {
1859 None => panic!("signature index refers to a type out of bounds"),
1860 Some(ty) => match &ty.composite_type.inner {
1861 CompositeInnerType::Func(func_type) => {
1862 let entity = EntityType::Func(*sig_idx, Rc::clone(func_type));
1863 if type_size_budget < entity.size() {
1864 continue;
1865 }
1866 self.funcs.push((*sig_idx, Rc::clone(func_type)));
1867 entity
1868 }
1869 _ => panic!("a function type is required for function import"),
1870 },
1871 }
1872 }
1873 }
1874
1875 wasmparser::TypeRef::FuncExact(_) => panic!("Unexpected func_exact import"),
1876
1877 wasmparser::TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }) => {
1878 let can_add_tag = self.tags.len() < self.config.max_tags;
1879 if !self.config.exceptions_enabled || !can_add_tag {
1880 continue;
1881 } else {
1882 match available_types.get(*func_type_idx as usize) {
1883 None => {
1884 panic!("function type index for tag refers to a type out of bounds")
1885 }
1886 Some(ty) => match &ty.composite_type.inner {
1887 CompositeInnerType::Func(func_type) => {
1888 let tag_type = TagType {
1889 func_type_idx: *func_type_idx,
1890 func_type: Rc::clone(func_type),
1891 };
1892 let entity = EntityType::Tag(tag_type.clone());
1893 if type_size_budget < entity.size() {
1894 continue;
1895 }
1896 self.tags.push(tag_type);
1897 entity
1898 }
1899 _ => panic!("a function type is required for tag import"),
1900 },
1901 }
1902 }
1903 }
1904
1905 wasmparser::TypeRef::Table(table_ty) => {
1906 let table_ty = TableType::try_from(*table_ty).unwrap();
1907 let entity = EntityType::Table(table_ty);
1908 let type_size = entity.size();
1909 if type_size_budget < type_size || !self.can_add_local_or_import_table() {
1910 continue;
1911 }
1912 self.type_size += type_size;
1913 self.tables.push(table_ty);
1914 entity
1915 }
1916
1917 wasmparser::TypeRef::Memory(memory_ty) => {
1918 let memory_ty = MemoryType::from(*memory_ty);
1919 let entity = EntityType::Memory(memory_ty);
1920 let type_size = entity.size();
1921 if type_size_budget < type_size || !self.can_add_local_or_import_memory() {
1922 continue;
1923 }
1924 self.type_size += type_size;
1925 self.memories.push(memory_ty);
1926 entity
1927 }
1928
1929 wasmparser::TypeRef::Global(global_ty) => {
1930 let global_ty = GlobalType::try_from(*global_ty).unwrap();
1931 let entity = EntityType::Global(global_ty);
1932 let type_size = entity.size();
1933 if type_size_budget < type_size || !self.can_add_local_or_import_global() {
1934 continue;
1935 }
1936 self.type_size += type_size;
1937 self.globals.push(global_ty);
1938 entity
1939 }
1940 };
1941 new_imports.push(Import {
1942 module: import.module.to_string(),
1943 name: import.name.to_string(),
1944 entity_type,
1945 });
1946 self.num_imports += 1;
1947 }
1948
1949 let mut recgrp_start_idx = self.types.len();
1951 for size in new_recgrps {
1952 self.rec_groups
1953 .push(recgrp_start_idx..recgrp_start_idx + size);
1954 recgrp_start_idx += size;
1955 }
1956 for ty in available_types {
1957 self.add_type(ty);
1958 }
1959 self.push_arbitrary_import_groups(new_imports, u)?;
1960
1961 Ok(())
1962 }
1963
1964 #[cfg(feature = "wasmparser")]
1974 fn push_arbitrary_import_groups(
1975 &mut self,
1976 imports: Vec<Import>,
1977 u: &mut Unstructured,
1978 ) -> Result<()> {
1979 let mut imports = imports.into_iter().peekable();
1980 while let Some(import) = imports.next() {
1981 match self.arbitrary_import_group_kind(u)? {
1982 ImportsKind::Single => self.imports.push(Imports::Single(import)),
1983 ImportsKind::Compact1 => {
1984 let module = import.module.clone();
1985 let mut items = vec![import];
1986 while imports.peek().is_some_and(|import| import.module == module)
1987 && u.arbitrary().unwrap_or(false)
1988 {
1989 items.push(imports.next().unwrap());
1990 }
1991 self.imports.push(Imports::Compact1 { module, items });
1992 }
1993 ImportsKind::Compact2 => {
1994 let module = import.module.clone();
1995 let entity_type = import.entity_type.clone();
1996 let mut names = vec![import.name];
1997 while imports.peek().is_some_and(|import| {
1998 import.module == module && import.entity_type == entity_type
1999 }) && u.arbitrary().unwrap_or(false)
2000 {
2001 names.push(imports.next().unwrap().name);
2002 }
2003 self.imports.push(Imports::Compact2 {
2004 module,
2005 entity_type,
2006 names,
2007 });
2008 }
2009 }
2010 }
2011 Ok(())
2012 }
2013
2014 fn type_of(&self, kind: ExportKind, index: u32) -> EntityType {
2015 match kind {
2016 ExportKind::Global => EntityType::Global(self.globals[index as usize]),
2017 ExportKind::Memory => EntityType::Memory(self.memories[index as usize]),
2018 ExportKind::Table => EntityType::Table(self.tables[index as usize]),
2019 ExportKind::Func => {
2020 let (_idx, ty) = &self.funcs[index as usize];
2021 EntityType::Func(u32::MAX, ty.clone())
2022 }
2023 ExportKind::Tag => EntityType::Tag(self.tags[index as usize].clone()),
2024 }
2025 }
2026
2027 fn ty(&self, idx: u32) -> &SubType {
2028 &self.types[idx as usize]
2029 }
2030
2031 fn func_types(&self) -> impl Iterator<Item = (u32, &FuncType)> + '_ {
2032 self.func_types
2033 .iter()
2034 .copied()
2035 .map(move |type_i| (type_i, &**self.func_type(type_i)))
2036 }
2037
2038 fn func_type(&self, idx: u32) -> &Rc<FuncType> {
2039 match &self.ty(idx).composite_type.inner {
2040 CompositeInnerType::Func(f) => f,
2041 _ => panic!("types[{idx}] is not a func type"),
2042 }
2043 }
2044
2045 fn tags(&self) -> impl Iterator<Item = (u32, &TagType)> + '_ {
2046 self.tags
2047 .iter()
2048 .enumerate()
2049 .map(move |(i, ty)| (i as u32, ty))
2050 }
2051
2052 fn funcs(&self) -> impl Iterator<Item = (u32, &Rc<FuncType>)> + '_ {
2053 self.funcs
2054 .iter()
2055 .enumerate()
2056 .map(move |(i, (_, ty))| (i as u32, ty))
2057 }
2058
2059 fn has_tag_func_types(&self) -> bool {
2060 self.tag_func_types().next().is_some()
2061 }
2062
2063 fn tag_func_types(&self) -> impl Iterator<Item = u32> + '_ {
2064 self.func_types
2065 .iter()
2066 .copied()
2067 .filter(move |i| self.func_type(*i).results.is_empty())
2068 }
2069
2070 fn arbitrary_valtype(&self, u: &mut Unstructured) -> Result<ValType> {
2071 #[derive(PartialEq, Eq, PartialOrd, Ord)]
2072 enum ValTypeClass {
2073 I32,
2074 I64,
2075 F32,
2076 F64,
2077 V128,
2078 Ref,
2079 }
2080
2081 let mut val_classes: Vec<_> = self
2082 .valtypes
2083 .iter()
2084 .map(|vt| match vt {
2085 ValType::I32 => ValTypeClass::I32,
2086 ValType::I64 => ValTypeClass::I64,
2087 ValType::F32 => ValTypeClass::F32,
2088 ValType::F64 => ValTypeClass::F64,
2089 ValType::V128 => ValTypeClass::V128,
2090 ValType::Ref(_) => ValTypeClass::Ref,
2091 })
2092 .collect();
2093 val_classes.sort_unstable();
2094 val_classes.dedup();
2095
2096 match u.choose(&val_classes)? {
2097 ValTypeClass::I32 => Ok(ValType::I32),
2098 ValTypeClass::I64 => Ok(ValType::I64),
2099 ValTypeClass::F32 => Ok(ValType::F32),
2100 ValTypeClass::F64 => Ok(ValType::F64),
2101 ValTypeClass::V128 => Ok(ValType::V128),
2102 ValTypeClass::Ref => Ok(ValType::Ref(self.arbitrary_ref_type(u)?)),
2103 }
2104 }
2105
2106 fn arbitrary_global_type(&self, u: &mut Unstructured) -> Result<GlobalType> {
2107 let val_type = self.arbitrary_valtype(u)?;
2108 let shared = match val_type {
2110 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {
2111 self.arbitrary_shared(u)?
2112 }
2113 ValType::Ref(r) => self.is_shared_ref_type(r),
2114 };
2115 Ok(GlobalType {
2116 val_type,
2117 mutable: u.arbitrary()?,
2118 shared,
2119 })
2120 }
2121
2122 fn arbitrary_tag_type(&self, u: &mut Unstructured) -> Result<TagType> {
2123 let candidate_func_types: Vec<_> = self.tag_func_types().collect();
2124 arbitrary_tag_type(u, &candidate_func_types, |ty_idx| {
2125 self.func_type(ty_idx).clone()
2126 })
2127 }
2128
2129 fn arbitrary_tags(&mut self, u: &mut Unstructured) -> Result<()> {
2130 if !self.config.exceptions_enabled || !self.has_tag_func_types() {
2131 return Ok(());
2132 }
2133
2134 arbitrary_loop(u, self.config.min_tags, self.config.max_tags, |u| {
2135 if !self.can_add_local_or_import_tag() {
2136 return Ok(false);
2137 }
2138 self.tags.push(self.arbitrary_tag_type(u)?);
2139 self.num_defined_tags += 1;
2140 Ok(true)
2141 })
2142 }
2143
2144 fn arbitrary_funcs(&mut self, u: &mut Unstructured) -> Result<()> {
2145 if self.func_types.is_empty() {
2146 return Ok(());
2147 }
2148
2149 let unshared_func_types: Vec<_> = self
2154 .func_types
2155 .iter()
2156 .copied()
2157 .filter(|&i| !self.is_shared_type(i))
2158 .collect();
2159 if unshared_func_types.is_empty() {
2160 return Ok(());
2161 }
2162
2163 arbitrary_loop(u, self.config.min_funcs, self.config.max_funcs, |u| {
2164 if !self.can_add_local_or_import_func() {
2165 return Ok(false);
2166 }
2167 let max = unshared_func_types.len() - 1;
2168 let ty = unshared_func_types[u.int_in_range(0..=max)?];
2169 self.funcs.push((ty, self.func_type(ty).clone()));
2170 self.num_defined_funcs += 1;
2171 Ok(true)
2172 })
2173 }
2174
2175 fn arbitrary_tables(&mut self, u: &mut Unstructured) -> Result<()> {
2176 arbitrary_loop(
2177 u,
2178 self.config.min_tables as usize,
2179 self.config.max_tables,
2180 |u| {
2181 if !self.can_add_local_or_import_table() {
2182 return Ok(false);
2183 }
2184 let ty = arbitrary_table_type(u, self.config(), Some(self))?;
2185 self.add_arbitrary_table_of_type(ty, u)?;
2186 Ok(true)
2187 },
2188 )
2189 }
2190
2191 fn arbitrary_table_init(
2197 &mut self,
2198 u: &mut Unstructured,
2199 ty: RefType,
2200 ) -> Result<Option<ConstExpr>> {
2201 if !self.config.gc_enabled {
2202 assert!(ty.nullable);
2203 return Ok(None);
2204 }
2205 if ty.nullable && u.arbitrary()? {
2208 return Ok(None);
2209 }
2210 let expr = self.arbitrary_const_expr(ValType::Ref(ty), u, false)?;
2213 Ok(Some(expr))
2214 }
2215
2216 fn arbitrary_memories(&mut self, u: &mut Unstructured) -> Result<()> {
2217 arbitrary_loop(
2218 u,
2219 self.config.min_memories as usize,
2220 self.config.max_memories,
2221 |u| {
2222 if !self.can_add_local_or_import_memory() {
2223 return Ok(false);
2224 }
2225 let ty = arbitrary_memtype(u, self.config())?;
2226 self.add_arbitrary_memory_of_type(ty)?;
2227 Ok(true)
2228 },
2229 )
2230 }
2231
2232 fn add_arbitrary_global_of_type(
2234 &mut self,
2235 ty: GlobalType,
2236 u: &mut Unstructured,
2237 ) -> Result<u32> {
2238 let expr = self.arbitrary_const_expr(ty.val_type, u, true)?;
2239 let global_idx = self.globals.len() as u32;
2240 self.globals.push(ty);
2241 self.defined_globals.push((global_idx, expr));
2242 Ok(global_idx)
2243 }
2244
2245 fn add_arbitrary_memory_of_type(&mut self, ty: MemoryType) -> Result<u32> {
2247 let memory_idx = self.memories.len() as u32;
2248 self.num_defined_memories += 1;
2249 self.memories.push(ty);
2250 Ok(memory_idx)
2251 }
2252
2253 fn add_arbitrary_table_of_type(&mut self, ty: TableType, u: &mut Unstructured) -> Result<u32> {
2255 let expr = self.arbitrary_table_init(u, ty.element_type)?;
2256 let table_idx = self.tables.len() as u32;
2257 self.tables.push(ty);
2258 self.defined_tables.push(expr);
2259 Ok(table_idx)
2260 }
2261
2262 fn arbitrary_const_expr(
2264 &mut self,
2265 ty: ValType,
2266 u: &mut Unstructured,
2267 allow_defined_globals: bool,
2268 ) -> Result<ConstExpr> {
2269 #[derive(Clone, Copy)]
2270 enum Choice {
2271 GlobalGet(u32),
2272 I32Const,
2273 I64Const,
2274 F32Const,
2275 F64Const,
2276 V128Const,
2277 ExtendedConst,
2278 RefNull(HeapType),
2279 RefFunc(u32),
2280 StructNew(u32),
2281 StructNewDefault(u32),
2282 ArrayNew(u32),
2283 ArrayNewDefault(u32),
2284 ArrayNewFixed(u32),
2285 RefI31 { shared: bool },
2286 AnyConvertExtern { nullable: bool, shared: bool },
2287 ExternConvertAny { nullable: bool, shared: bool },
2288 }
2289
2290 fn encode_instrs(instrs: impl IntoIterator<Item = Instruction>) -> Vec<u8> {
2291 let mut bytes = Vec::new();
2292 for instr in instrs {
2293 instr.encode(&mut bytes);
2294 }
2295 bytes
2296 }
2297
2298 fn arbitrary_extended_const(u: &mut Unstructured<'_>, ty: ValType) -> Result<Vec<u8>> {
2306 use wasm_encoder::Instruction::*;
2307
2308 assert!(ty == ValType::I32 || ty == ValType::I64);
2311 let add = if ty == ValType::I32 { I32Add } else { I64Add };
2312 let sub = if ty == ValType::I32 { I32Sub } else { I64Sub };
2313 let mul = if ty == ValType::I32 { I32Mul } else { I64Mul };
2314 let const_: fn(&mut Unstructured<'_>) -> Result<Instruction> = if ty == ValType::I32 {
2315 |u| u.arbitrary().map(I32Const)
2316 } else {
2317 |u| u.arbitrary().map(I64Const)
2318 };
2319
2320 let mut instrs = Vec::new();
2325 let mut needed = 1;
2326 while needed > 0 {
2327 let choice = if u.is_empty() || instrs.len() > 10 {
2331 0
2332 } else {
2333 u.int_in_range(0..=3)?
2334 };
2335 match choice {
2336 0 => {
2337 instrs.push(const_(u)?);
2338 needed -= 1;
2339 }
2340 1 => {
2341 instrs.push(add.clone());
2342 needed += 1;
2343 }
2344 2 => {
2345 instrs.push(sub.clone());
2346 needed += 1;
2347 }
2348 3 => {
2349 instrs.push(mul.clone());
2350 needed += 1;
2351 }
2352 _ => unreachable!(),
2353 }
2354 }
2355 Ok(encode_instrs(instrs.into_iter().rev()))
2356 }
2357
2358 fn abstract_ref(nullable: bool, shared: bool, ty: AbstractHeapType) -> RefType {
2359 RefType::new_abstract(ty, nullable, shared)
2360 }
2361
2362 fn concrete_ref(nullable: bool, ty: u32) -> RefType {
2363 RefType {
2364 nullable,
2365 heap_type: HeapType::Concrete(ty),
2366 }
2367 }
2368
2369 fn type_is_defaultable(field: StorageType) -> bool {
2370 field.unpack().is_defaultable()
2371 }
2372
2373 fn can_use_struct_new(ty: &SubType) -> bool {
2374 ty.composite_type.descriptor.is_none()
2375 }
2376
2377 fn can_use_struct_new_default(ty: &SubType) -> bool {
2378 can_use_struct_new(ty)
2379 && ty
2380 .unwrap_struct()
2381 .fields
2382 .iter()
2383 .all(|f| type_is_defaultable(f.element_type))
2384 }
2385
2386 fn const_expr_bytes_for_array_length(
2387 module: &mut Module,
2388 u: &mut Unstructured<'_>,
2389 allow_defined_globals: bool,
2390 fuel: &mut u32,
2391 ) -> Result<Vec<u8>> {
2392 if module.config.limit_arrays_in_const_exprs {
2393 let size = u.int_in_range(0..=*fuel)?;
2394 *fuel -= size;
2395 return Ok(encode_instrs([Instruction::I32Const(size as i32)]));
2396 }
2397
2398 const_expr_bytes(module, ValType::I32, u, allow_defined_globals, fuel)
2399 }
2400
2401 fn const_expr_bytes(
2402 module: &mut Module,
2403 ty: ValType,
2404 u: &mut Unstructured<'_>,
2405 allow_defined_globals: bool,
2406 fuel: &mut u32,
2407 ) -> Result<Vec<u8>> {
2408 let mut choices = Vec::new();
2409
2410 for i in module.globals_for_const_expr(ty, allow_defined_globals) {
2411 choices.push(Choice::GlobalGet(i));
2412 }
2413
2414 let ty = match ty {
2415 ValType::Ref(_) => ty,
2416 _ => module.arbitrary_matching_val_type(u, ty)?,
2417 };
2418 match ty {
2419 ValType::I32 => {
2420 choices.push(Choice::I32Const);
2421 if module.config.extended_const_enabled {
2422 choices.push(Choice::ExtendedConst);
2423 }
2424 }
2425 ValType::I64 => {
2426 choices.push(Choice::I64Const);
2427 if module.config.extended_const_enabled {
2428 choices.push(Choice::ExtendedConst);
2429 }
2430 }
2431 ValType::F32 => choices.push(Choice::F32Const),
2432 ValType::F64 => choices.push(Choice::F64Const),
2433 ValType::V128 => choices.push(Choice::V128Const),
2434 ValType::Ref(ref_ty) => {
2435 if ref_ty.nullable {
2436 choices.push(Choice::RefNull(ref_ty.heap_type));
2437 }
2438
2439 for (func_idx, (type_idx, _)) in module.funcs.iter().enumerate() {
2440 let produced = concrete_ref(false, *type_idx);
2441 if module.ref_type_is_sub_type(produced, ref_ty) {
2442 choices.push(Choice::RefFunc(func_idx as u32));
2443 }
2444 }
2445
2446 if module.config.gc_enabled {
2447 for &type_idx in &module.struct_types {
2448 let produced = concrete_ref(false, type_idx);
2449 if !module.ref_type_is_sub_type(produced, ref_ty) {
2450 continue;
2451 }
2452 if can_use_struct_new(module.ty(type_idx))
2453 && (*fuel > 0
2454 || module.ty(type_idx).unwrap_struct().fields.is_empty())
2455 {
2456 choices.push(Choice::StructNew(type_idx));
2457 }
2458 if can_use_struct_new_default(module.ty(type_idx)) {
2459 choices.push(Choice::StructNewDefault(type_idx));
2460 }
2461 }
2462
2463 for &type_idx in &module.array_types {
2464 let produced = concrete_ref(false, type_idx);
2465 if !module.ref_type_is_sub_type(produced, ref_ty) {
2466 continue;
2467 }
2468 if *fuel > 0 {
2469 choices.push(Choice::ArrayNew(type_idx));
2470 choices.push(Choice::ArrayNewFixed(type_idx));
2471 if type_is_defaultable(
2472 module.ty(type_idx).unwrap_array().0.element_type,
2473 ) {
2474 choices.push(Choice::ArrayNewDefault(type_idx));
2475 }
2476 }
2477 }
2478
2479 let produced_i31 = abstract_ref(false, false, AbstractHeapType::I31);
2480 if *fuel > 0 && module.ref_type_is_sub_type(produced_i31, ref_ty) {
2481 choices.push(Choice::RefI31 { shared: false });
2482 }
2483
2484 if module.config.shared_everything_threads_enabled {
2485 let produced_i31 = abstract_ref(false, true, AbstractHeapType::I31);
2486 if *fuel > 0 && module.ref_type_is_sub_type(produced_i31, ref_ty) {
2487 choices.push(Choice::RefI31 { shared: true });
2488 }
2489 }
2490
2491 match ref_ty.heap_type {
2492 HeapType::Abstract {
2493 shared,
2494 ty: AbstractHeapType::Any,
2495 } if *fuel > 0 => {
2496 choices.push(Choice::AnyConvertExtern {
2497 nullable: ref_ty.nullable,
2498 shared,
2499 });
2500 }
2501 HeapType::Abstract {
2502 shared,
2503 ty: AbstractHeapType::Extern,
2504 } if *fuel > 0 => {
2505 choices.push(Choice::ExternConvertAny {
2506 nullable: ref_ty.nullable,
2507 shared,
2508 });
2509 }
2510 _ => {}
2511 }
2512 }
2513 }
2514 }
2515
2516 let choice = *u.choose(&choices)?;
2517 *fuel = fuel.saturating_sub(1);
2518 Ok(match choice {
2519 Choice::GlobalGet(i) => encode_instrs([Instruction::GlobalGet(i)]),
2520 Choice::I32Const => encode_instrs([Instruction::I32Const(u.arbitrary()?)]),
2521 Choice::I64Const => encode_instrs([Instruction::I64Const(u.arbitrary()?)]),
2522 Choice::F32Const => {
2523 encode_instrs([Instruction::F32Const(u.arbitrary::<f32>()?.into())])
2524 }
2525 Choice::F64Const => {
2526 encode_instrs([Instruction::F64Const(u.arbitrary::<f64>()?.into())])
2527 }
2528 Choice::V128Const => encode_instrs([Instruction::V128Const(u.arbitrary()?)]),
2529 Choice::ExtendedConst => arbitrary_extended_const(u, ty)?,
2530 Choice::RefNull(heap_type) => encode_instrs([Instruction::RefNull(heap_type)]),
2531 Choice::RefFunc(i) => encode_instrs([Instruction::RefFunc(i)]),
2532 Choice::StructNew(type_idx) => {
2533 let mut bytes = Vec::new();
2534 let field_types: Vec<_> = module
2535 .ty(type_idx)
2536 .unwrap_struct()
2537 .fields
2538 .iter()
2539 .map(|field| field.element_type.unpack())
2540 .collect();
2541 for field_ty in field_types {
2542 bytes.extend(const_expr_bytes(
2543 module,
2544 field_ty,
2545 u,
2546 allow_defined_globals,
2547 fuel,
2548 )?);
2549 }
2550 bytes.extend(encode_instrs([Instruction::StructNew(type_idx)]));
2551 bytes
2552 }
2553 Choice::StructNewDefault(type_idx) => {
2554 encode_instrs([Instruction::StructNewDefault(type_idx)])
2555 }
2556 Choice::ArrayNew(type_idx) => {
2557 let mut bytes = Vec::new();
2558 let elem_ty = module.ty(type_idx).unwrap_array().0.element_type.unpack();
2559 bytes.extend(const_expr_bytes(
2560 module,
2561 elem_ty,
2562 u,
2563 allow_defined_globals,
2564 fuel,
2565 )?);
2566 bytes.extend(const_expr_bytes_for_array_length(
2567 module,
2568 u,
2569 allow_defined_globals,
2570 fuel,
2571 )?);
2572 bytes.extend(encode_instrs([Instruction::ArrayNew(type_idx)]));
2573 bytes
2574 }
2575 Choice::ArrayNewDefault(type_idx) => {
2576 let mut bytes =
2577 const_expr_bytes_for_array_length(module, u, allow_defined_globals, fuel)?;
2578 bytes.extend(encode_instrs([Instruction::ArrayNewDefault(type_idx)]));
2579 bytes
2580 }
2581 Choice::ArrayNewFixed(type_idx) => {
2582 let array_size = u.int_in_range(0..=3)?;
2583 let array_size = u32::try_from(array_size).unwrap();
2584 let elem_ty = module.ty(type_idx).unwrap_array().0.element_type.unpack();
2585 let mut bytes = Vec::new();
2586 for _ in 0..array_size {
2587 bytes.extend(const_expr_bytes(
2588 module,
2589 elem_ty,
2590 u,
2591 allow_defined_globals,
2592 fuel,
2593 )?);
2594 }
2595 bytes.extend(encode_instrs([Instruction::ArrayNewFixed {
2596 array_type_index: type_idx,
2597 array_size,
2598 }]));
2599 bytes
2600 }
2601 Choice::RefI31 { shared } => {
2602 let mut bytes =
2603 const_expr_bytes(module, ValType::I32, u, allow_defined_globals, fuel)?;
2604 bytes.extend(encode_instrs([if shared {
2605 Instruction::RefI31Shared
2606 } else {
2607 Instruction::RefI31
2608 }]));
2609 bytes
2610 }
2611 Choice::AnyConvertExtern { nullable, shared } => {
2612 let mut bytes = const_expr_bytes(
2613 module,
2614 ValType::Ref(abstract_ref(nullable, shared, AbstractHeapType::Extern)),
2615 u,
2616 allow_defined_globals,
2617 fuel,
2618 )?;
2619 bytes.extend(encode_instrs([Instruction::AnyConvertExtern]));
2620 bytes
2621 }
2622 Choice::ExternConvertAny { nullable, shared } => {
2623 let mut bytes = const_expr_bytes(
2624 module,
2625 ValType::Ref(abstract_ref(nullable, shared, AbstractHeapType::Any)),
2626 u,
2627 allow_defined_globals,
2628 fuel,
2629 )?;
2630 bytes.extend(encode_instrs([Instruction::ExternConvertAny]));
2631 bytes
2632 }
2633 })
2634 }
2635
2636 let mut fuel = self.config.const_expr_fuel;
2637 Ok(ConstExpr::raw(const_expr_bytes(
2638 self,
2639 ty,
2640 u,
2641 allow_defined_globals,
2642 &mut fuel,
2643 )?))
2644 }
2645
2646 fn arbitrary_globals(&mut self, u: &mut Unstructured) -> Result<()> {
2647 arbitrary_loop(u, self.config.min_globals, self.config.max_globals, |u| {
2648 if !self.can_add_local_or_import_global() {
2649 return Ok(false);
2650 }
2651
2652 let ty = self.arbitrary_global_type(u)?;
2653 self.add_arbitrary_global_of_type(ty, u)?;
2654
2655 Ok(true)
2656 })
2657 }
2658
2659 fn required_exports(&mut self, u: &mut Unstructured) -> Result<bool> {
2660 let example_module = if let Some(wasm) = self.config.exports.clone() {
2661 wasm
2662 } else {
2663 return Ok(false);
2664 };
2665
2666 #[cfg(feature = "wasmparser")]
2667 {
2668 self._required_exports(u, &example_module)?;
2669 Ok(true)
2670 }
2671 #[cfg(not(feature = "wasmparser"))]
2672 {
2673 let _ = (example_module, u);
2674 panic!("support for `exports` was disabled at compile time");
2675 }
2676 }
2677
2678 #[cfg(feature = "wasmparser")]
2679 fn _required_exports(&mut self, u: &mut Unstructured, example_module: &[u8]) -> Result<()> {
2680 let mut required_exports: Vec<wasmparser::Export> = vec![];
2681 let mut validator = wasmparser::Validator::new();
2682 let exports_types = validator
2683 .validate_all(&example_module)
2684 .expect("Failed to validate `exports` Wasm");
2685 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
2686 match payload.expect("Failed to read `exports` Wasm") {
2687 wasmparser::Payload::ExportSection(export_reader) => {
2688 required_exports = export_reader
2689 .into_iter()
2690 .collect::<Result<_, _>>()
2691 .expect("Failed to read `exports` export section");
2692 }
2693 _ => {}
2694 }
2695 }
2696
2697 let exports_types = exports_types.as_ref();
2699 let check_and_get_func_type =
2700 |id: wasmparser::types::CoreTypeId| -> (Rc<FuncType>, SubType) {
2701 let subtype = exports_types.get(id).unwrap_or_else(|| {
2702 panic!("Unable to get subtype for {id:?} in `exports` Wasm")
2703 });
2704 match &subtype.composite_type.inner {
2705 wasmparser::CompositeInnerType::Func(func_type) => {
2706 assert!(
2707 subtype.is_final,
2708 "Subtype {subtype:?} from `exports` Wasm is not final"
2709 );
2710 assert!(
2711 subtype.supertype_idx.is_none(),
2712 "Subtype {subtype:?} from `exports` Wasm has non-empty supertype"
2713 );
2714 let func_type = Rc::new(FuncType {
2715 params: func_type
2716 .params()
2717 .iter()
2718 .copied()
2719 .map(|t| t.try_into().unwrap())
2720 .collect(),
2721 results: func_type
2722 .results()
2723 .iter()
2724 .copied()
2725 .map(|t| t.try_into().unwrap())
2726 .collect(),
2727 });
2728 let subtype = SubType {
2729 is_final: true,
2730 supertype: None,
2731 depth: 1,
2732 composite_type: CompositeType::new_func(
2733 Rc::clone(&func_type),
2734 subtype.composite_type.shared,
2735 ),
2736 };
2737 (func_type, subtype)
2738 }
2739 _ => panic!(
2740 "Unable to handle type {:?} from `exports` Wasm",
2741 subtype.composite_type
2742 ),
2743 }
2744 };
2745 for export in required_exports {
2746 let new_index = match exports_types
2747 .entity_type_from_export(&export)
2748 .unwrap_or_else(|| {
2749 panic!("Unable to get type from export {export:?} in `exports` Wasm",)
2750 }) {
2751 wasmparser::types::EntityType::Func(id) => {
2753 let (func_type, subtype) = check_and_get_func_type(id);
2754 self.rec_groups.push(self.types.len()..self.types.len() + 1);
2755 let type_index = self.add_type(subtype);
2756 let func_index = self.funcs.len() as u32;
2757 self.funcs.push((type_index, func_type));
2758 self.num_defined_funcs += 1;
2759 func_index
2760 }
2761 wasmparser::types::EntityType::Global(global_type) => {
2763 self.add_arbitrary_global_of_type(global_type.try_into().unwrap(), u)?
2764 }
2765 wasmparser::types::EntityType::Memory(memory_type) => {
2767 self.add_arbitrary_memory_of_type(memory_type.into())?
2768 }
2769 wasmparser::types::EntityType::Table(table_type) => {
2771 self.add_arbitrary_table_of_type(table_type.try_into().unwrap(), u)?
2772 }
2773 wasmparser::types::EntityType::Tag(id) => {
2775 let (func_type, subtype) = check_and_get_func_type(id);
2776 self.rec_groups.push(self.types.len()..self.types.len() + 1);
2777 let type_index = self.add_type(subtype);
2778 let tag_index = self.tags.len() as u32;
2779 self.tags.push(TagType {
2780 func_type_idx: type_index,
2781 func_type: func_type,
2782 });
2783 self.num_defined_tags += 1;
2784 tag_index
2785 }
2786 wasmparser::types::EntityType::FuncExact(_) => {
2787 panic!("Unexpected func_export: {export:?}",);
2788 }
2789 };
2790 self.exports
2791 .push((export.name.to_string(), export.kind.into(), new_index));
2792 self.export_names.insert(export.name.to_string());
2793 }
2794
2795 Ok(())
2796 }
2797
2798 fn arbitrary_exports(&mut self, u: &mut Unstructured) -> Result<()> {
2799 if self.config.max_type_size < self.type_size && !self.config.export_everything {
2800 return Ok(());
2801 }
2802
2803 let mut choices: Vec<Vec<(ExportKind, u32)>> = Vec::with_capacity(6);
2805 choices.push(
2806 (0..self.funcs.len())
2807 .map(|i| (ExportKind::Func, i as u32))
2808 .collect(),
2809 );
2810 choices.push(
2811 (0..self.tables.len())
2812 .map(|i| (ExportKind::Table, i as u32))
2813 .collect(),
2814 );
2815 choices.push(
2816 (0..self.memories.len())
2817 .map(|i| (ExportKind::Memory, i as u32))
2818 .collect(),
2819 );
2820 choices.push(
2821 (0..self.globals.len())
2822 .map(|i| (ExportKind::Global, i as u32))
2823 .collect(),
2824 );
2825
2826 if self.config.export_everything {
2829 for choices_by_kind in choices {
2830 for (kind, idx) in choices_by_kind {
2831 let name = unique_string(1_000, &mut self.export_names, u)?;
2832 self.add_arbitrary_export(name, kind, idx)?;
2833 }
2834 }
2835 return Ok(());
2836 }
2837
2838 arbitrary_loop(u, self.config.min_exports, self.config.max_exports, |u| {
2839 let max_size = self.config.max_type_size - self.type_size;
2845 for list in choices.iter_mut() {
2846 list.retain(|(kind, idx)| self.type_of(*kind, *idx).size() + 1 < max_size);
2847 }
2848 choices.retain(|list| !list.is_empty());
2849 if choices.is_empty() {
2850 return Ok(false);
2851 }
2852
2853 let name = unique_string(1_000, &mut self.export_names, u)?;
2856 let list = u.choose(&choices)?;
2857 let (kind, idx) = *u.choose(list)?;
2858 self.add_arbitrary_export(name, kind, idx)?;
2859 Ok(true)
2860 })
2861 }
2862
2863 fn add_arbitrary_export(&mut self, name: String, kind: ExportKind, idx: u32) -> Result<()> {
2864 let ty = self.type_of(kind, idx);
2865 self.type_size += 1 + ty.size();
2866 if self.type_size <= self.config.max_type_size {
2867 self.exports.push((name, kind, idx));
2868 Ok(())
2869 } else {
2870 Err(arbitrary::Error::IncorrectFormat)
2874 }
2875 }
2876
2877 fn arbitrary_start(&mut self, u: &mut Unstructured) -> Result<()> {
2878 if !self.config.allow_start_export {
2879 return Ok(());
2880 }
2881
2882 let mut choices = Vec::with_capacity(self.funcs.len());
2883
2884 for (func_idx, ty) in self.funcs() {
2885 if ty.params.is_empty() && ty.results.is_empty() {
2886 choices.push(func_idx);
2887 }
2888 }
2889
2890 if !choices.is_empty() && u.arbitrary().unwrap_or(false) {
2891 let f = *u.choose(&choices)?;
2892 self.start = Some(f);
2893 }
2894
2895 Ok(())
2896 }
2897
2898 fn arbitrary_elems(&mut self, u: &mut Unstructured) -> Result<()> {
2899 let mut global_i32 = vec![];
2901 let mut global_i64 = vec![];
2902 if !self.config.disallow_traps {
2903 for i in self.globals_for_const_expr(ValType::I32, true) {
2904 global_i32.push(i);
2905 }
2906 for i in self.globals_for_const_expr(ValType::I64, true) {
2907 global_i64.push(i);
2908 }
2909 }
2910 let disallow_traps = self.config.disallow_traps;
2911 let arbitrary_active_elem =
2912 |u: &mut Unstructured, min_mem_size: u64, table: Option<u32>, table_ty: &TableType| {
2913 let global_choices = if table_ty.table64 {
2914 &global_i64
2915 } else {
2916 &global_i32
2917 };
2918 let (offset, max_size_hint) = if !global_choices.is_empty() && u.arbitrary()? {
2919 let g = u.choose(&global_choices)?;
2920 (Offset::Global(*g), None)
2921 } else {
2922 let max_mem_size = if disallow_traps {
2923 table_ty.minimum
2924 } else if table_ty.table64 {
2925 u64::MAX
2926 } else {
2927 u64::from(u32::MAX)
2928 };
2929 let offset = arbitrary_offset(u, min_mem_size, max_mem_size, 0)?;
2930 let max_size_hint = if disallow_traps
2931 || (offset <= min_mem_size
2932 && u.int_in_range(0..=CHANCE_OFFSET_INBOUNDS)? != 0)
2933 {
2934 Some(min_mem_size - offset)
2935 } else {
2936 None
2937 };
2938
2939 let offset = if table_ty.table64 {
2940 Offset::Const64(offset as i64)
2941 } else {
2942 Offset::Const32(offset as i32)
2943 };
2944 (offset, max_size_hint)
2945 };
2946 Ok((ElementKind::Active { table, offset }, max_size_hint))
2947 };
2948
2949 type GenElemSegment<'a> =
2953 dyn Fn(&mut Unstructured) -> Result<(ElementKind, Option<u64>)> + 'a;
2954 let mut choices: Vec<Box<GenElemSegment>> = Vec::new();
2955
2956 if self.config.bulk_memory_enabled {
2959 choices.push(Box::new(|_| Ok((ElementKind::Passive, None))));
2960 choices.push(Box::new(|_| Ok((ElementKind::Declared, None))));
2961 }
2962
2963 for (i, ty) in self.tables.iter().enumerate() {
2964 if ty.minimum == 0 && u.int_in_range(0..=CHANCE_SEGMENT_ON_EMPTY)? != 0 {
2969 continue;
2970 }
2971
2972 let minimum = ty.minimum;
2973 let ty = *ty;
2976 if i == 0 && ty.element_type == RefType::FUNCREF {
2977 choices.push(Box::new(move |u| {
2978 arbitrary_active_elem(u, minimum, None, &ty)
2979 }));
2980 }
2981 if self.config.bulk_memory_enabled {
2982 let idx = Some(i as u32);
2983 choices.push(Box::new(move |u| {
2984 arbitrary_active_elem(u, minimum, idx, &ty)
2985 }));
2986 }
2987 }
2988
2989 if choices.is_empty() {
2990 return Ok(());
2991 }
2992
2993 let mut total_elements = 0_usize;
2994
2995 arbitrary_loop(
2996 u,
2997 self.config.min_element_segments,
2998 self.config.max_element_segments,
2999 |u| {
3000 let (kind, max_size_hint) = u.choose(&choices)?(u)?;
3003 let max = max_size_hint
3004 .map(|i| usize::try_from(i).unwrap())
3005 .unwrap_or(self.config.max_elements);
3006
3007 let ty = match kind {
3011 ElementKind::Passive | ElementKind::Declared => self.arbitrary_ref_type(u)?,
3012 ElementKind::Active { table, .. } => {
3013 let idx = table.unwrap_or(0);
3014 self.arbitrary_matching_ref_type(u, self.tables[idx as usize].element_type)?
3015 }
3016 };
3017
3018 let can_use_function_list = ty == RefType::FUNCREF;
3022 if !self.config.reference_types_enabled {
3023 assert!(can_use_function_list);
3024 }
3025
3026 let mut func_candidates = Vec::new();
3029 if can_use_function_list {
3030 match ty.heap_type {
3031 HeapType::Abstract {
3032 ty: AbstractHeapType::Func,
3033 ..
3034 } => {
3035 func_candidates.extend(0..self.funcs.len() as u32);
3036 }
3037 HeapType::Concrete(ty) => {
3038 for (i, (fty, _)) in self.funcs.iter().enumerate() {
3039 if *fty == ty {
3040 func_candidates.push(i as u32);
3041 }
3042 }
3043 }
3044 _ => {}
3045 }
3046 }
3047
3048 let max = (total_elements.saturating_sub(self.config.max_elements)).min(max);
3052
3053 let items = if !self.config.reference_types_enabled
3058 || (can_use_function_list && u.arbitrary()?)
3059 {
3060 let mut init = vec![];
3061 if func_candidates.len() > 0 {
3062 arbitrary_loop(u, self.config.min_elements, max, |u| {
3063 let func_idx = *u.choose(&func_candidates)?;
3064 init.push(func_idx);
3065 Ok(true)
3066 })?;
3067 }
3068 total_elements += init.len();
3069 Elements::Functions(init)
3070 } else {
3071 let mut init = vec![];
3072 arbitrary_loop(u, self.config.min_elements, max, |u| {
3073 init.push(self.arbitrary_const_expr(ValType::Ref(ty), u, true)?);
3074 Ok(true)
3075 })?;
3076 total_elements += init.len();
3077 Elements::Expressions(init)
3078 };
3079
3080 self.elems.push(ElementSegment { kind, ty, items });
3081 Ok(true)
3082 },
3083 )
3084 }
3085
3086 fn arbitrary_code(&mut self, u: &mut Unstructured) -> Result<()> {
3087 self.compute_interesting_values();
3088
3089 self.code.reserve(self.num_defined_funcs);
3090 let mut allocs = CodeBuilderAllocations::new(
3091 self,
3092 self.config.exports.is_some() || self.config.module_shape.is_some(),
3093 );
3094 for (idx, ty) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() {
3095 let shared = self.is_shared_type(*idx);
3096 let body = self.arbitrary_func_body(u, ty, &mut allocs, shared)?;
3097 self.code.push(body);
3098 }
3099 allocs.finish(u, self)?;
3100 Ok(())
3101 }
3102
3103 fn arbitrary_func_body(
3104 &self,
3105 u: &mut Unstructured,
3106 ty: &FuncType,
3107 allocs: &mut CodeBuilderAllocations,
3108 shared: bool,
3109 ) -> Result<Code> {
3110 let mut locals = self.arbitrary_locals(u)?;
3111 let builder = allocs.builder(ty, &mut locals, shared);
3112 let instructions = if self.config.allow_invalid_funcs && u.arbitrary().unwrap_or(false) {
3113 Instructions::Arbitrary(arbitrary_vec_u8(u)?)
3114 } else {
3115 Instructions::Generated(builder.arbitrary(u, self)?)
3116 };
3117
3118 Ok(Code {
3119 locals,
3120 instructions,
3121 })
3122 }
3123
3124 fn arbitrary_locals(&self, u: &mut Unstructured) -> Result<Vec<ValType>> {
3125 let mut ret = Vec::new();
3126 arbitrary_loop(u, 0, 100, |u| {
3127 ret.push(self.arbitrary_valtype(u)?);
3128 Ok(true)
3129 })?;
3130 Ok(ret)
3131 }
3132
3133 fn arbitrary_data(&mut self, u: &mut Unstructured) -> Result<()> {
3134 let memories = self.memories.len() as u32;
3137 if memories == 0 && !self.config.bulk_memory_enabled {
3138 return Ok(());
3139 }
3140 let disallow_traps = self.config.disallow_traps;
3141 let mut choices32: Vec<
3142 Box<dyn Fn(&mut Unstructured, &MemoryType, usize) -> Result<Offset>>,
3143 > = vec![];
3144 fn min(ty: &MemoryType) -> u64 {
3145 ty.minimum.saturating_mul(u64::from(ty.page_size()))
3146 }
3147 choices32.push(Box::new(|u, ty, data_len| {
3148 let min = u32::try_from(min(ty)).unwrap_or(u32::MAX).into();
3149 let max = if disallow_traps { min } else { u32::MAX.into() };
3150 Ok(Offset::Const32(
3151 arbitrary_offset(u, min, max, data_len)? as i32
3152 ))
3153 }));
3154 let mut choices64: Vec<
3155 Box<dyn Fn(&mut Unstructured, &MemoryType, usize) -> Result<Offset>>,
3156 > = vec![];
3157 choices64.push(Box::new(|u, ty, data_len| {
3158 let min = min(ty);
3159 let max = if disallow_traps { min } else { u64::MAX };
3160 Ok(Offset::Const64(
3161 arbitrary_offset(u, min, max, data_len)? as i64
3162 ))
3163 }));
3164 if !self.config.disallow_traps {
3165 for i in self.globals_for_const_expr(ValType::I32, true) {
3166 choices32.push(Box::new(move |_, _, _| Ok(Offset::Global(i))));
3167 }
3168 for i in self.globals_for_const_expr(ValType::I64, true) {
3169 choices64.push(Box::new(move |_, _, _| Ok(Offset::Global(i))));
3170 }
3171 }
3172
3173 let mut memories = Vec::new();
3179 for (i, mem) in self.memories.iter().enumerate() {
3180 if mem.minimum > 0 || u.int_in_range(0..=CHANCE_SEGMENT_ON_EMPTY)? == 0 {
3181 memories.push(i as u32);
3182 }
3183 }
3184
3185 if memories.is_empty() && !self.config.bulk_memory_enabled {
3189 return Ok(());
3190 }
3191
3192 arbitrary_loop(
3193 u,
3194 self.config.min_data_segments,
3195 self.config.max_data_segments,
3196 |u| {
3197 let mut init: Vec<u8> = u.arbitrary()?;
3198
3199 let kind =
3204 if self.config.bulk_memory_enabled && (memories.is_empty() || u.arbitrary()?) {
3205 DataSegmentKind::Passive
3206 } else {
3207 let memory_index = *u.choose(&memories)?;
3208 let mem = &self.memories[memory_index as usize];
3209 let f = if mem.memory64 {
3210 u.choose(&choices64)?
3211 } else {
3212 u.choose(&choices32)?
3213 };
3214 let mut offset = f(u, mem, init.len())?;
3215
3216 if self.config.disallow_traps {
3221 let page_size = u64::from(mem.page_size());
3222 let max_size = (u64::MAX / page_size).min(mem.minimum) * page_size;
3223 init.truncate(max_size as usize);
3224 let max_offset = max_size - init.len() as u64;
3225 match &mut offset {
3226 Offset::Const32(x) => {
3227 *x = (*x as u64).min(max_offset) as i32;
3228 }
3229 Offset::Const64(x) => {
3230 *x = (*x as u64).min(max_offset) as i64;
3231 }
3232 Offset::Global(_) => unreachable!(),
3233 }
3234 }
3235 DataSegmentKind::Active {
3236 offset,
3237 memory_index,
3238 }
3239 };
3240 self.data.push(DataSegment { kind, init });
3241 Ok(true)
3242 },
3243 )
3244 }
3245
3246 fn params_results(&self, ty: &BlockType) -> (Vec<ValType>, Vec<ValType>) {
3247 match ty {
3248 BlockType::Empty => (vec![], vec![]),
3249 BlockType::Result(t) => (vec![], vec![*t]),
3250 BlockType::FunctionType(ty) => {
3251 let ty = self.func_type(*ty);
3252 (ty.params.to_vec(), ty.results.to_vec())
3253 }
3254 }
3255 }
3256
3257 fn globals_for_const_expr(
3260 &self,
3261 ty: ValType,
3262 allow_defined_globals: bool,
3263 ) -> impl Iterator<Item = u32> + '_ {
3264 let num_imported_globals = self.globals.len() - self.defined_globals.len();
3267 let max_global = if self.config.gc_enabled && allow_defined_globals {
3268 self.globals.len()
3269 } else {
3270 num_imported_globals
3271 };
3272
3273 self.globals[..max_global]
3274 .iter()
3275 .enumerate()
3276 .filter_map(move |(i, g)| {
3277 if !g.mutable && self.val_type_is_sub_type(g.val_type, ty) {
3281 Some(i as u32)
3282 } else {
3283 None
3284 }
3285 })
3286 }
3287
3288 fn compute_interesting_values(&mut self) {
3289 debug_assert!(self.interesting_values32.is_empty());
3290 debug_assert!(self.interesting_values64.is_empty());
3291
3292 let mut interesting_values32 = HashSet::new();
3293 let mut interesting_values64 = HashSet::new();
3294
3295 let mut interesting = |val: u64| {
3296 interesting_values32.insert(val as u32);
3297 interesting_values64.insert(val);
3298 };
3299
3300 interesting(0);
3302
3303 interesting(u8::MAX as _);
3305 interesting(u16::MAX as _);
3306 interesting(u32::MAX as _);
3307 interesting(u64::MAX);
3308
3309 interesting(i8::MIN as _);
3311 interesting(i16::MIN as _);
3312 interesting(i32::MIN as _);
3313 interesting(i64::MIN as _);
3314
3315 for i in 0..64 {
3316 interesting(1 << i);
3318
3319 interesting(!(1 << i));
3321
3322 interesting((1 << i) - 1);
3324
3325 interesting(((1_i64 << 63) >> i) as _);
3327 }
3328
3329 for pattern in [0b01010101, 0b00010001, 0b00010001, 0b00000001] {
3331 for b in [pattern, !pattern] {
3332 interesting(u64::from_ne_bytes([b, b, b, b, b, b, b, b]));
3333 }
3334 }
3335
3336 let mut interesting_f64 = |x: f64| interesting(x.to_bits());
3338 interesting_f64(0.0);
3339 interesting_f64(-0.0);
3340 interesting_f64(f64::INFINITY);
3341 interesting_f64(f64::NEG_INFINITY);
3342 interesting_f64(f64::EPSILON);
3343 interesting_f64(-f64::EPSILON);
3344 interesting_f64(f64::MIN);
3345 interesting_f64(f64::MIN_POSITIVE);
3346 interesting_f64(f64::MAX);
3347 interesting_f64(f64::NAN);
3348 let mut interesting_f32 = |x: f32| interesting(x.to_bits() as _);
3349 interesting_f32(0.0);
3350 interesting_f32(-0.0);
3351 interesting_f32(f32::INFINITY);
3352 interesting_f32(f32::NEG_INFINITY);
3353 interesting_f32(f32::EPSILON);
3354 interesting_f32(-f32::EPSILON);
3355 interesting_f32(f32::MIN);
3356 interesting_f32(f32::MIN_POSITIVE);
3357 interesting_f32(f32::MAX);
3358 interesting_f32(f32::NAN);
3359
3360 for t in self.tables.iter() {
3362 interesting(t.minimum as _);
3363 if let Some(x) = t.minimum.checked_add(1) {
3364 interesting(x as _);
3365 }
3366
3367 if let Some(x) = t.maximum {
3368 interesting(x as _);
3369 if let Some(y) = x.checked_add(1) {
3370 interesting(y as _);
3371 }
3372 }
3373 }
3374
3375 for m in self.memories.iter() {
3377 let min = m.minimum.saturating_mul(m.page_size().into());
3378 interesting(min);
3379 for i in 0..5 {
3380 if let Some(x) = min.checked_add(1 << i) {
3381 interesting(x);
3382 }
3383 if let Some(x) = min.checked_sub(1 << i) {
3384 interesting(x);
3385 }
3386 }
3387
3388 if let Some(max) = m.maximum {
3389 let max = max.saturating_mul(m.page_size().into());
3390 interesting(max);
3391 for i in 0..5 {
3392 if let Some(x) = max.checked_add(1 << i) {
3393 interesting(x);
3394 }
3395 if let Some(x) = max.checked_sub(1 << i) {
3396 interesting(x);
3397 }
3398 }
3399 }
3400 }
3401
3402 self.interesting_values32.extend(interesting_values32);
3403 self.interesting_values64.extend(interesting_values64);
3404
3405 self.interesting_values32.sort();
3407 self.interesting_values64.sort();
3408 }
3409
3410 fn arbitrary_const_instruction(
3411 &self,
3412 ty: ValType,
3413 u: &mut Unstructured<'_>,
3414 ) -> Result<Instruction> {
3415 debug_assert!(self.interesting_values32.len() > 0);
3416 debug_assert!(self.interesting_values64.len() > 0);
3417 match ty {
3418 ValType::I32 => Ok(Instruction::I32Const(if u.arbitrary()? {
3419 *u.choose(&self.interesting_values32)? as i32
3420 } else {
3421 u.arbitrary()?
3422 })),
3423 ValType::I64 => Ok(Instruction::I64Const(if u.arbitrary()? {
3424 *u.choose(&self.interesting_values64)? as i64
3425 } else {
3426 u.arbitrary()?
3427 })),
3428 ValType::F32 => Ok(Instruction::F32Const(if u.arbitrary()? {
3429 f32::from_bits(*u.choose(&self.interesting_values32)?).into()
3430 } else {
3431 u.arbitrary::<f32>()?.into()
3432 })),
3433 ValType::F64 => Ok(Instruction::F64Const(if u.arbitrary()? {
3434 f64::from_bits(*u.choose(&self.interesting_values64)?).into()
3435 } else {
3436 u.arbitrary::<f64>()?.into()
3437 })),
3438 ValType::V128 => Ok(Instruction::V128Const(if u.arbitrary()? {
3439 let upper = (*u.choose(&self.interesting_values64)? as i128) << 64;
3440 let lower = *u.choose(&self.interesting_values64)? as i128;
3441 upper | lower
3442 } else {
3443 u.arbitrary()?
3444 })),
3445 ValType::Ref(ty) => {
3446 assert!(ty.nullable);
3447 Ok(Instruction::RefNull(ty.heap_type))
3448 }
3449 }
3450 }
3451
3452 fn propagate_shared<T>(&mut self, must_share: bool, mut f: impl FnMut(&mut Self) -> T) -> T {
3453 let tmp = mem::replace(&mut self.must_share, must_share);
3454 let result = f(self);
3455 self.must_share = tmp;
3456 result
3457 }
3458
3459 fn arbitrary_shared(&self, u: &mut Unstructured) -> Result<bool> {
3460 if self.must_share {
3461 Ok(true)
3462 } else {
3463 Ok(self.config.shared_everything_threads_enabled && u.ratio(1, 4)?)
3464 }
3465 }
3466
3467 fn is_shared_ref_type(&self, ty: RefType) -> bool {
3468 match ty.heap_type {
3469 HeapType::Abstract { shared, .. } => shared,
3470 HeapType::Concrete(i) | HeapType::Exact(i) => {
3471 self.types[i as usize].composite_type.shared
3472 }
3473 }
3474 }
3475
3476 fn is_shared_type(&self, index: u32) -> bool {
3477 let index = usize::try_from(index).unwrap();
3478 let ty = self.types.get(index).unwrap();
3479 ty.composite_type.shared
3480 }
3481}
3482
3483pub(crate) fn arbitrary_limits64(
3484 u: &mut Unstructured,
3485 min_minimum: Option<u64>,
3486 max_minimum: u64,
3487 max_required: bool,
3488 max_inbounds: u64,
3489) -> Result<(u64, Option<u64>)> {
3490 assert!(
3491 min_minimum.unwrap_or(0) <= max_minimum,
3492 "{} <= {max_minimum}",
3493 min_minimum.unwrap_or(0),
3494 );
3495 assert!(
3496 min_minimum.unwrap_or(0) <= max_inbounds,
3497 "{} <= {max_inbounds}",
3498 min_minimum.unwrap_or(0),
3499 );
3500
3501 let min = gradually_grow(u, min_minimum.unwrap_or(0), max_inbounds, max_minimum)?;
3502 assert!(min <= max_minimum, "{min} <= {max_minimum}");
3503
3504 let max = if max_required || u.arbitrary().unwrap_or(false) {
3505 Some(u.int_in_range(min..=max_minimum)?)
3506 } else {
3507 None
3508 };
3509 assert!(min <= max.unwrap_or(min), "{min} <= {}", max.unwrap_or(min));
3510
3511 Ok((min, max))
3512}
3513
3514pub(crate) fn configured_valtypes(config: &Config) -> Vec<ValType> {
3515 let mut valtypes = Vec::with_capacity(25);
3516 valtypes.push(ValType::I32);
3517 valtypes.push(ValType::I64);
3518 if config.allow_floats {
3519 valtypes.push(ValType::F32);
3520 valtypes.push(ValType::F64);
3521 }
3522 if config.simd_enabled {
3523 valtypes.push(ValType::V128);
3524 }
3525 if config.gc_enabled && config.reference_types_enabled {
3526 for nullable in [
3527 true,
3534 ] {
3535 use AbstractHeapType::*;
3536 let abs_ref_types = [
3537 Any, Eq, I31, Array, Struct, None, Func, NoFunc, Extern, NoExtern,
3538 ];
3539 valtypes.extend(
3540 abs_ref_types
3541 .iter()
3542 .map(|&ty| ValType::Ref(RefType::new_abstract(ty, nullable, false))),
3543 );
3544 if config.shared_everything_threads_enabled {
3545 valtypes.extend(
3546 abs_ref_types
3547 .iter()
3548 .map(|&ty| ValType::Ref(RefType::new_abstract(ty, nullable, true))),
3549 );
3550 }
3551 }
3552 } else if config.reference_types_enabled {
3553 valtypes.push(ValType::EXTERNREF);
3554 valtypes.push(ValType::FUNCREF);
3555 }
3556 valtypes
3557}
3558
3559pub(crate) fn arbitrary_table_type(
3560 u: &mut Unstructured,
3561 config: &Config,
3562 module: Option<&Module>,
3563) -> Result<TableType> {
3564 let table64 = config.memory64_enabled && u.arbitrary()?;
3565 let max_inbounds = 10_000;
3568 let min_elements = if config.disallow_traps { Some(1) } else { None };
3569 let mut max_elements = min_elements.unwrap_or(0).max(config.max_table_elements);
3570 if !table64 {
3572 max_elements = max_elements.min(u64::from(u32::MAX));
3573 }
3574 let (minimum, maximum) = arbitrary_limits64(
3575 u,
3576 min_elements,
3577 max_elements,
3578 config.table_max_size_required,
3579 max_inbounds.min(max_elements),
3580 )?;
3581 if config.disallow_traps {
3582 assert!(minimum > 0);
3583 }
3584 let element_type = match module {
3585 Some(module) => module.arbitrary_ref_type(u)?,
3586 None => RefType::FUNCREF,
3587 };
3588
3589 let shared = match module {
3591 Some(module) => module.is_shared_ref_type(element_type),
3592 None => false,
3593 };
3594
3595 Ok(TableType {
3596 element_type,
3597 minimum,
3598 maximum,
3599 table64,
3600 shared,
3601 })
3602}
3603
3604pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &Config) -> Result<MemoryType> {
3605 let shared = config.threads_enabled && u.ratio(1, 4)?;
3608
3609 let memory64 = config.memory64_enabled && u.arbitrary()?;
3610 let page_size_log2 = if config.custom_page_sizes_enabled && u.arbitrary()? {
3611 Some(if u.arbitrary()? { 0 } else { 16 })
3612 } else {
3613 None
3614 };
3615
3616 let min_pages = if config.disallow_traps { Some(1) } else { None };
3617 let max_pages = min_pages.unwrap_or(0).max(if memory64 {
3618 u64::try_from(config.max_memory64_bytes >> page_size_log2.unwrap_or(16))
3619 .unwrap_or(u64::MAX)
3623 } else {
3624 u32::try_from(config.max_memory32_bytes >> page_size_log2.unwrap_or(16))
3625 .unwrap_or(u32::MAX)
3628 .into()
3629 });
3630
3631 let max_all_mems_in_bytes = 1 << 30;
3633 let max_this_mem_in_bytes = max_all_mems_in_bytes / u64::try_from(config.max_memories).unwrap();
3634 let max_inbounds = max_this_mem_in_bytes >> page_size_log2.unwrap_or(16);
3635 let max_inbounds = max_inbounds.clamp(min_pages.unwrap_or(0), max_pages);
3636
3637 let (minimum, maximum) = arbitrary_limits64(
3638 u,
3639 min_pages,
3640 max_pages,
3641 config.memory_max_size_required || shared,
3642 max_inbounds,
3643 )?;
3644
3645 Ok(MemoryType {
3646 minimum,
3647 maximum,
3648 memory64,
3649 shared,
3650 page_size_log2,
3651 })
3652}
3653
3654pub(crate) fn arbitrary_tag_type(
3655 u: &mut Unstructured,
3656 candidate_func_types: &[u32],
3657 get_func_type: impl FnOnce(u32) -> Rc<FuncType>,
3658) -> Result<TagType> {
3659 let max = candidate_func_types.len() - 1;
3660 let ty = candidate_func_types[u.int_in_range(0..=max)?];
3661 Ok(TagType {
3662 func_type_idx: ty,
3663 func_type: get_func_type(ty),
3664 })
3665}
3666
3667fn gradually_grow(u: &mut Unstructured, min: u64, max_inbounds: u64, max: u64) -> Result<u64> {
3675 if min == max {
3676 return Ok(min);
3677 }
3678 let x = {
3679 let min = min as f64;
3680 let max = max as f64;
3681 let max_inbounds = max_inbounds as f64;
3682 let x = u.arbitrary::<u32>()?;
3683 let x = f64::from(x);
3684 let x = map_custom(
3685 x,
3686 f64::from(u32::MIN)..f64::from(u32::MAX),
3687 min..max_inbounds,
3688 min..max,
3689 );
3690 assert!(min <= x, "{min} <= {x}");
3691 assert!(x <= max, "{x} <= {max}");
3692 x.round() as u64
3693 };
3694
3695 return Ok(x.clamp(min, max));
3698
3699 fn map_custom(
3706 value: f64,
3707 input: Range<f64>,
3708 output_inbounds: Range<f64>,
3709 output: Range<f64>,
3710 ) -> f64 {
3711 assert!(!value.is_nan(), "{}", value);
3712 assert!(value.is_finite(), "{}", value);
3713 assert!(input.start < input.end, "{} < {}", input.start, input.end);
3714 assert!(
3715 output.start < output.end,
3716 "{} < {}",
3717 output.start,
3718 output.end
3719 );
3720 assert!(value >= input.start, "{} >= {}", value, input.start);
3721 assert!(value <= input.end, "{} <= {}", value, input.end);
3722 assert!(
3723 output.start <= output_inbounds.start,
3724 "{} <= {}",
3725 output.start,
3726 output_inbounds.start
3727 );
3728 assert!(
3729 output_inbounds.end <= output.end,
3730 "{} <= {}",
3731 output_inbounds.end,
3732 output.end
3733 );
3734
3735 let x = map_linear(value, input, 0.0..1.0);
3736 let result = if x < PCT_INBOUNDS {
3737 if output_inbounds.start == output_inbounds.end {
3738 output_inbounds.start
3739 } else {
3740 let unscaled = x * x * x * x * x * x;
3741 map_linear(unscaled, 0.0..1.0, output_inbounds)
3742 }
3743 } else {
3744 map_linear(x, 0.0..1.0, output.clone())
3745 };
3746
3747 assert!(result >= output.start, "{} >= {}", result, output.start);
3748 assert!(result <= output.end, "{} <= {}", result, output.end);
3749 result
3750 }
3751
3752 fn map_linear(
3757 value: f64,
3758 Range {
3759 start: in_low,
3760 end: in_high,
3761 }: Range<f64>,
3762 Range {
3763 start: out_low,
3764 end: out_high,
3765 }: Range<f64>,
3766 ) -> f64 {
3767 assert!(!value.is_nan(), "{}", value);
3768 assert!(value.is_finite(), "{}", value);
3769 assert!(in_low < in_high, "{in_low} < {in_high}");
3770 assert!(out_low < out_high, "{out_low} < {out_high}");
3771 assert!(value >= in_low, "{value} >= {in_low}");
3772 assert!(value <= in_high, "{value} <= {in_high}");
3773
3774 let dividend = out_high - out_low;
3775 let divisor = in_high - in_low;
3776 let slope = dividend / divisor;
3777 let result = out_low + (slope * (value - in_low));
3778
3779 assert!(result >= out_low, "{result} >= {out_low}");
3780 assert!(result <= out_high, "{result} <= {out_high}");
3781 result
3782 }
3783}
3784
3785fn arbitrary_offset(
3789 u: &mut Unstructured,
3790 limit_min: u64,
3791 limit_max: u64,
3792 segment_size: usize,
3793) -> Result<u64> {
3794 let size = u64::try_from(segment_size).unwrap();
3795
3796 if size > limit_min {
3799 u.int_in_range(0..=limit_max)
3800 } else {
3801 gradually_grow(u, 0, limit_min - size, limit_max)
3802 }
3803}
3804
3805fn arbitrary_vec_u8(u: &mut Unstructured) -> Result<Vec<u8>> {
3806 let size = u.arbitrary_len::<u8>()?;
3807 Ok(u.bytes(size)?.to_vec())
3808}
3809
3810impl EntityType {
3811 fn size(&self) -> u32 {
3812 match self {
3813 EntityType::Tag(_)
3814 | EntityType::Global(_)
3815 | EntityType::Table(_)
3816 | EntityType::Memory(_) => 1,
3817 EntityType::Func(_, ty) => 1 + (ty.params.len() + ty.results.len()) as u32,
3818 }
3819 }
3820}
3821
3822#[derive(Clone, Copy, Debug, Default)]
3833#[cfg_attr(
3834 feature = "serde",
3835 derive(serde_derive::Deserialize, serde_derive::Serialize)
3836)]
3837pub struct InstructionKinds(pub(crate) FlagSet<InstructionKind>);
3838
3839impl InstructionKinds {
3840 pub fn new(kinds: &[InstructionKind]) -> Self {
3842 Self(kinds.iter().fold(FlagSet::default(), |ks, k| ks | *k))
3843 }
3844
3845 pub fn all() -> Self {
3847 Self(FlagSet::full())
3848 }
3849
3850 pub fn none() -> Self {
3852 Self(FlagSet::default())
3853 }
3854
3855 #[inline]
3857 pub fn contains(&self, kind: InstructionKind) -> bool {
3858 self.0.contains(kind)
3859 }
3860
3861 pub fn without_floats(&self) -> Self {
3863 let mut floatless = self.0;
3864 if floatless.contains(InstructionKind::Numeric) {
3865 floatless -= InstructionKind::Numeric;
3866 floatless |= InstructionKind::NumericInt;
3867 }
3868 if floatless.contains(InstructionKind::Vector) {
3869 floatless -= InstructionKind::Vector;
3870 floatless |= InstructionKind::VectorInt;
3871 }
3872 if floatless.contains(InstructionKind::Memory) {
3873 floatless -= InstructionKind::Memory;
3874 floatless |= InstructionKind::MemoryInt;
3875 }
3876 Self(floatless)
3877 }
3878}
3879
3880flags! {
3881 #[allow(missing_docs)]
3884 #[cfg_attr(feature = "_internal_cli", derive(serde_derive::Deserialize))]
3885 pub enum InstructionKind: u16 {
3886 NumericInt = 1 << 0,
3887 Numeric = (1 << 1) | (1 << 0),
3888 VectorInt = 1 << 2,
3889 Vector = (1 << 3) | (1 << 2),
3890 Reference = 1 << 4,
3891 Parametric = 1 << 5,
3892 Variable = 1 << 6,
3893 Table = 1 << 7,
3894 MemoryInt = 1 << 8,
3895 Memory = (1 << 9) | (1 << 8),
3896 Control = 1 << 10,
3897 Aggregate = 1 << 11,
3898 }
3899}
3900
3901impl FromStr for InstructionKinds {
3902 type Err = String;
3903 fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
3904 let mut kinds = vec![];
3905 for part in s.split(",") {
3906 let kind = InstructionKind::from_str(part)?;
3907 kinds.push(kind);
3908 }
3909 Ok(InstructionKinds::new(&kinds))
3910 }
3911}
3912
3913impl FromStr for InstructionKind {
3914 type Err = String;
3915 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3916 match s.to_lowercase().as_str() {
3917 "numeric_non_float" => Ok(InstructionKind::NumericInt),
3918 "numeric" => Ok(InstructionKind::Numeric),
3919 "vector_non_float" => Ok(InstructionKind::VectorInt),
3920 "vector" => Ok(InstructionKind::Vector),
3921 "reference" => Ok(InstructionKind::Reference),
3922 "parametric" => Ok(InstructionKind::Parametric),
3923 "variable" => Ok(InstructionKind::Variable),
3924 "table" => Ok(InstructionKind::Table),
3925 "memory_non_float" => Ok(InstructionKind::MemoryInt),
3926 "memory" => Ok(InstructionKind::Memory),
3927 "control" => Ok(InstructionKind::Control),
3928 "aggregate" => Ok(InstructionKind::Aggregate),
3929 _ => Err(format!("unknown instruction kind: {s}")),
3930 }
3931 }
3932}
3933
3934#[cfg(feature = "wasmparser")]
3937impl TryFrom<wasmparser::FuncType> for FuncType {
3938 type Error = ();
3939
3940 fn try_from(value: wasmparser::FuncType) -> Result<Self, Self::Error> {
3941 Ok(FuncType {
3942 params: value
3943 .params()
3944 .iter()
3945 .copied()
3946 .map(|ty| ty.try_into().map_err(|_| ()))
3947 .collect::<Result<Vec<_>, _>>()?,
3948 results: value
3949 .results()
3950 .iter()
3951 .copied()
3952 .map(|ty| ty.try_into().map_err(|_| ()))
3953 .collect::<Result<Vec<_>, _>>()?,
3954 })
3955 }
3956}
3957
3958#[cfg(feature = "wasmparser")]
3959impl TryFrom<wasmparser::CompositeType> for CompositeType {
3960 type Error = ();
3961
3962 fn try_from(value: wasmparser::CompositeType) -> Result<Self, Self::Error> {
3963 let inner_type = match value.inner {
3964 wasmparser::CompositeInnerType::Func(func_type) => {
3965 CompositeInnerType::Func(Rc::new(func_type.try_into()?))
3966 }
3967 wasmparser::CompositeInnerType::Array(array_type) => {
3968 CompositeInnerType::Array(array_type.try_into().map_err(|_| ())?)
3969 }
3970 wasmparser::CompositeInnerType::Struct(struct_type) => {
3971 CompositeInnerType::Struct(struct_type.try_into().map_err(|_| ())?)
3972 }
3973 wasmparser::CompositeInnerType::Cont(_) => {
3974 panic!("continuation type is not supported by wasm-smith currently.")
3975 }
3976 };
3977
3978 Ok(CompositeType {
3979 inner: inner_type,
3980 shared: value.shared,
3981 descriptor: value
3982 .descriptor_idx
3983 .map(|idx| idx.as_module_index().ok_or(()))
3984 .transpose()?,
3985 describes: value
3986 .describes_idx
3987 .map(|idx| idx.as_module_index().ok_or(()))
3988 .transpose()?,
3989 })
3990 }
3991}
3992
3993#[cfg(feature = "wasmparser")]
3994impl TryFrom<wasmparser::SubType> for SubType {
3995 type Error = ();
3996
3997 fn try_from(value: wasmparser::SubType) -> Result<Self, Self::Error> {
3998 Ok(SubType {
3999 is_final: value.is_final,
4000 supertype: value
4001 .supertype_idx
4002 .map(|idx| idx.as_module_index().ok_or(()))
4003 .transpose()?,
4004 composite_type: value.composite_type.try_into()?,
4005 depth: 1,
4008 })
4009 }
4010}