1mod code_builder;
4pub(crate) mod encode;
5mod terminate;
6
7use crate::{arbitrary_loop, limited_string, unique_string, Config};
8use arbitrary::{Arbitrary, Result, Unstructured};
9use code_builder::CodeBuilderAllocations;
10use flagset::{flags, FlagSet};
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, ExportKind, FieldType, HeapType, RefType,
19 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<Import>,
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 const_expr_choices: Vec<Box<dyn Fn(&mut Unstructured, ValType) -> Result<ConstExpr>>>,
150
151 max_type_limit: MaxTypeLimit,
153
154 interesting_values32: Vec<u32>,
157 interesting_values64: Vec<u64>,
158}
159
160impl<'a> Arbitrary<'a> for Module {
161 fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
162 Module::new(Config::default(), u)
163 }
164}
165
166impl fmt::Debug for Module {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 f.debug_struct("Module")
169 .field("config", &self.config)
170 .field(&"...", &"...")
171 .finish()
172 }
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub(crate) enum DuplicateImportsBehavior {
177 Allowed,
178 Disallowed,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182enum AllowEmptyRecGroup {
183 Yes,
184 No,
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188enum MaxTypeLimit {
189 ModuleTypes,
190 Num(u32),
191}
192
193impl Module {
194 pub fn config(&self) -> &Config {
196 &self.config
197 }
198
199 pub fn new(config: Config, u: &mut Unstructured<'_>) -> Result<Self> {
202 Self::new_internal(config, u, DuplicateImportsBehavior::Allowed)
203 }
204
205 pub(crate) fn new_internal(
206 config: Config,
207 u: &mut Unstructured<'_>,
208 duplicate_imports_behavior: DuplicateImportsBehavior,
209 ) -> Result<Self> {
210 let mut module = Module::empty(config, duplicate_imports_behavior);
211 module.build(u)?;
212 Ok(module)
213 }
214
215 fn empty(mut config: Config, duplicate_imports_behavior: DuplicateImportsBehavior) -> Self {
216 config.sanitize();
217 Module {
218 config,
219 duplicate_imports_behavior,
220 valtypes: Vec::new(),
221 types: Vec::new(),
222 rec_groups: Vec::new(),
223 can_subtype: Vec::new(),
224 super_to_sub_types: HashMap::new(),
225 should_encode_types: false,
226 imports: Vec::new(),
227 should_encode_imports: false,
228 array_types: Vec::new(),
229 func_types: Vec::new(),
230 struct_types: Vec::new(),
231 num_imports: 0,
232 num_defined_tags: 0,
233 num_defined_funcs: 0,
234 defined_tables: Vec::new(),
235 num_defined_memories: 0,
236 defined_globals: Vec::new(),
237 tags: Vec::new(),
238 funcs: Vec::new(),
239 tables: Vec::new(),
240 globals: Vec::new(),
241 memories: Vec::new(),
242 exports: Vec::new(),
243 start: None,
244 elems: Vec::new(),
245 code: Vec::new(),
246 data: Vec::new(),
247 type_size: 0,
248 export_names: HashSet::new(),
249 const_expr_choices: Vec::new(),
250 max_type_limit: MaxTypeLimit::ModuleTypes,
251 interesting_values32: Vec::new(),
252 interesting_values64: Vec::new(),
253 must_share: false,
254 }
255 }
256}
257
258#[derive(Clone, Debug, PartialEq, Eq, Hash)]
259pub(crate) struct SubType {
260 pub(crate) is_final: bool,
261 pub(crate) supertype: Option<u32>,
262 pub(crate) composite_type: CompositeType,
263 depth: u32,
266}
267
268impl SubType {
269 fn unwrap_struct(&self) -> &StructType {
270 self.composite_type.unwrap_struct()
271 }
272
273 fn unwrap_func(&self) -> &Rc<FuncType> {
274 self.composite_type.unwrap_func()
275 }
276
277 fn unwrap_array(&self) -> &ArrayType {
278 self.composite_type.unwrap_array()
279 }
280}
281
282#[derive(Clone, Debug, PartialEq, Eq, Hash)]
283pub(crate) struct CompositeType {
284 pub inner: CompositeInnerType,
285 pub shared: bool,
286}
287
288impl CompositeType {
289 #[cfg(any(feature = "component-model", feature = "wasmparser"))]
290 pub(crate) fn new_func(func: Rc<FuncType>, shared: bool) -> Self {
291 Self {
292 inner: CompositeInnerType::Func(func),
293 shared,
294 }
295 }
296
297 fn unwrap_func(&self) -> &Rc<FuncType> {
298 match &self.inner {
299 CompositeInnerType::Func(f) => f,
300 _ => panic!("not a func"),
301 }
302 }
303
304 fn unwrap_array(&self) -> &ArrayType {
305 match &self.inner {
306 CompositeInnerType::Array(a) => a,
307 _ => panic!("not an array"),
308 }
309 }
310
311 fn unwrap_struct(&self) -> &StructType {
312 match &self.inner {
313 CompositeInnerType::Struct(s) => s,
314 _ => panic!("not a struct"),
315 }
316 }
317}
318
319impl From<&CompositeType> for wasm_encoder::CompositeType {
320 fn from(ty: &CompositeType) -> Self {
321 let inner = match &ty.inner {
322 CompositeInnerType::Array(a) => wasm_encoder::CompositeInnerType::Array(*a),
323 CompositeInnerType::Func(f) => wasm_encoder::CompositeInnerType::Func(
324 wasm_encoder::FuncType::new(f.params.iter().cloned(), f.results.iter().cloned()),
325 ),
326 CompositeInnerType::Struct(s) => wasm_encoder::CompositeInnerType::Struct(s.clone()),
327 };
328 wasm_encoder::CompositeType {
329 shared: ty.shared,
330 inner,
331 }
332 }
333}
334
335#[derive(Clone, Debug, PartialEq, Eq, Hash)]
336pub(crate) enum CompositeInnerType {
337 Array(ArrayType),
338 Func(Rc<FuncType>),
339 Struct(StructType),
340}
341
342#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
344pub(crate) struct FuncType {
345 pub(crate) params: Vec<ValType>,
347 pub(crate) results: Vec<ValType>,
349}
350
351#[derive(Clone, Debug, PartialEq, Eq, Hash)]
353pub(crate) struct Import {
354 pub(crate) module: String,
356 pub(crate) field: String,
358 pub(crate) entity_type: EntityType,
360}
361
362#[derive(Clone, Debug, PartialEq, Eq, Hash)]
364pub(crate) enum EntityType {
365 Global(GlobalType),
367 Table(TableType),
369 Memory(MemoryType),
371 Tag(TagType),
373 Func(u32, Rc<FuncType>),
375}
376
377#[derive(Clone, Debug, PartialEq, Eq, Hash)]
379pub(crate) struct TagType {
380 func_type_idx: u32,
382 func_type: Rc<FuncType>,
384}
385
386#[derive(Debug)]
387struct ElementSegment {
388 kind: ElementKind,
389 ty: RefType,
390 items: Elements,
391}
392
393#[derive(Debug)]
394enum ElementKind {
395 Passive,
396 Declared,
397 Active {
398 table: Option<u32>, offset: Offset,
400 },
401}
402
403#[derive(Debug)]
404enum Elements {
405 Functions(Vec<u32>),
406 Expressions(Vec<ConstExpr>),
407}
408
409#[derive(Debug)]
410struct Code {
411 locals: Vec<ValType>,
412 instructions: Instructions,
413}
414
415#[derive(Debug)]
416enum Instructions {
417 Generated(Vec<Instruction>),
418 Arbitrary(Vec<u8>),
419}
420
421#[derive(Debug)]
422struct DataSegment {
423 kind: DataSegmentKind,
424 init: Vec<u8>,
425}
426
427#[derive(Debug)]
428enum DataSegmentKind {
429 Passive,
430 Active { memory_index: u32, offset: Offset },
431}
432
433#[derive(Debug)]
434pub(crate) enum Offset {
435 Const32(i32),
436 Const64(i64),
437 Global(u32),
438}
439
440impl Module {
441 fn build(&mut self, u: &mut Unstructured) -> Result<()> {
442 self.valtypes = configured_valtypes(&self.config);
443
444 if self.arbitrary_imports_from_available(u)? {
450 self.arbitrary_types(u)?;
451 } else {
452 self.arbitrary_types(u)?;
453 self.arbitrary_imports(u)?;
454 }
455
456 self.should_encode_imports = !self.imports.is_empty() || u.arbitrary()?;
457
458 self.arbitrary_tags(u)?;
459 self.arbitrary_funcs(u)?;
460 self.arbitrary_tables(u)?;
461 self.arbitrary_memories(u)?;
462 self.arbitrary_globals(u)?;
463 if !self.required_exports(u)? {
464 self.arbitrary_exports(u)?;
465 };
466 self.should_encode_types = !self.types.is_empty() || u.arbitrary()?;
467 self.arbitrary_start(u)?;
468 self.arbitrary_elems(u)?;
469 self.arbitrary_data(u)?;
470 self.arbitrary_code(u)?;
471 Ok(())
472 }
473
474 #[inline]
475 fn val_type_is_sub_type(&self, a: ValType, b: ValType) -> bool {
476 match (a, b) {
477 (a, b) if a == b => true,
478 (ValType::Ref(a), ValType::Ref(b)) => self.ref_type_is_sub_type(a, b),
479 _ => false,
480 }
481 }
482
483 fn ref_type_is_sub_type(&self, a: RefType, b: RefType) -> bool {
485 if a == b {
486 return true;
487 }
488
489 if a.nullable && !b.nullable {
490 return false;
491 }
492
493 self.heap_type_is_sub_type(a.heap_type, b.heap_type)
494 }
495
496 fn heap_type_is_sub_type(&self, a: HeapType, b: HeapType) -> bool {
497 use AbstractHeapType::*;
498 use CompositeInnerType as CT;
499 use HeapType as HT;
500 match (a, b) {
501 (a, b) if a == b => true,
502
503 (
504 HT::Abstract {
505 shared: a_shared,
506 ty: a_ty,
507 },
508 HT::Abstract {
509 shared: b_shared,
510 ty: b_ty,
511 },
512 ) => {
513 a_shared == b_shared
514 && match (a_ty, b_ty) {
515 (Eq | I31 | Struct | Array | None, Any) => true,
516 (I31 | Struct | Array | None, Eq) => true,
517 (NoExtern, Extern) => true,
518 (NoFunc, Func) => true,
519 (None, I31 | Array | Struct) => true,
520 (NoExn, Exn) => true,
521 _ => false,
522 }
523 }
524
525 (HT::Concrete(a), HT::Abstract { shared, ty }) => {
526 let a_ty = &self.ty(a).composite_type;
527 if a_ty.shared != shared {
528 return false;
529 }
530 match ty {
531 Eq | Any => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
532 Struct => matches!(a_ty.inner, CT::Struct(_)),
533 Array => matches!(a_ty.inner, CT::Array(_)),
534 Func => matches!(a_ty.inner, CT::Func(_)),
535 _ => false,
536 }
537 }
538
539 (HT::Abstract { shared, ty }, HT::Concrete(b)) => {
540 let b_ty = &self.ty(b).composite_type;
541 if shared != b_ty.shared {
542 return false;
543 }
544 match ty {
545 None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
546 NoFunc => matches!(b_ty.inner, CT::Func(_)),
547 _ => false,
548 }
549 }
550
551 (HT::Concrete(mut a), HT::Concrete(b)) => loop {
552 if a == b {
553 return true;
554 }
555 if let Some(supertype) = self.ty(a).supertype {
556 a = supertype;
557 } else {
558 return false;
559 }
560 },
561 }
562 }
563
564 fn arbitrary_types(&mut self, u: &mut Unstructured) -> Result<()> {
565 assert!(self.config.min_types <= self.config.max_types);
566 while self.types.len() < self.config.min_types {
567 self.arbitrary_rec_group(u, AllowEmptyRecGroup::No)?;
568 }
569 while self.types.len() < self.config.max_types {
570 let keep_going = u.arbitrary().unwrap_or(false);
571 if !keep_going {
572 break;
573 }
574 self.arbitrary_rec_group(u, AllowEmptyRecGroup::Yes)?;
575 }
576 Ok(())
577 }
578
579 fn add_type(&mut self, ty: SubType) -> u32 {
580 let index = u32::try_from(self.types.len()).unwrap();
581
582 if let Some(supertype) = ty.supertype {
583 assert_eq!(self.is_shared_type(supertype), ty.composite_type.shared);
584 self.super_to_sub_types
585 .entry(supertype)
586 .or_default()
587 .push(index);
588 }
589
590 let list = match &ty.composite_type.inner {
591 CompositeInnerType::Array(_) => &mut self.array_types,
592 CompositeInnerType::Func(_) => &mut self.func_types,
593 CompositeInnerType::Struct(_) => &mut self.struct_types,
594 };
595 list.push(index);
596
597 const MAX_SUBTYPING_DEPTH: u32 = 60;
605 if !ty.is_final && ty.depth < MAX_SUBTYPING_DEPTH {
606 self.can_subtype.push(index);
607 }
608
609 self.types.push(ty);
610 index
611 }
612
613 fn arbitrary_rec_group(
614 &mut self,
615 u: &mut Unstructured,
616 kind: AllowEmptyRecGroup,
617 ) -> Result<()> {
618 let rec_group_start = self.types.len();
619
620 assert!(matches!(self.max_type_limit, MaxTypeLimit::ModuleTypes));
621
622 if self.config.gc_enabled {
623 if self.rec_groups.len() > 0 && u.ratio(1, u8::MAX)? {
625 return self.clone_rec_group(u, kind);
626 }
627
628 let max_rec_group_size = self.config.max_types - self.types.len();
630 let min_rec_group_size = match kind {
631 AllowEmptyRecGroup::Yes => 0,
632 AllowEmptyRecGroup::No => 1,
633 };
634 let rec_group_size = u.int_in_range(min_rec_group_size..=max_rec_group_size)?;
635 let type_ref_limit = u32::try_from(self.types.len() + rec_group_size).unwrap();
636 self.max_type_limit = MaxTypeLimit::Num(type_ref_limit);
637 for _ in 0..rec_group_size {
638 let ty = self.arbitrary_sub_type(u)?;
639 self.add_type(ty);
640 }
641 } else {
642 let type_ref_limit = u32::try_from(self.types.len()).unwrap();
643 self.max_type_limit = MaxTypeLimit::Num(type_ref_limit);
644 let ty = self.arbitrary_sub_type(u)?;
645 self.add_type(ty);
646 }
647
648 self.max_type_limit = MaxTypeLimit::ModuleTypes;
649
650 self.rec_groups.push(rec_group_start..self.types.len());
651 Ok(())
652 }
653
654 fn clone_rec_group(&mut self, u: &mut Unstructured, kind: AllowEmptyRecGroup) -> Result<()> {
655 let group = u.choose(&self.rec_groups)?.clone();
660 if group.is_empty() && kind == AllowEmptyRecGroup::No {
661 return Ok(());
662 }
663 if group.len() > self.config.max_types.saturating_sub(self.types.len()) {
664 return Ok(());
665 }
666
667 let new_rec_group_start = self.types.len();
675 for index in group {
676 let orig_ty_index = u32::try_from(index).unwrap();
677 let ty = self.ty(orig_ty_index).clone();
678 self.add_type(ty);
679 }
680 self.rec_groups.push(new_rec_group_start..self.types.len());
681 Ok(())
682 }
683
684 fn arbitrary_sub_type(&mut self, u: &mut Unstructured) -> Result<SubType> {
685 if !self.config.gc_enabled {
686 let shared = self.arbitrary_shared(u)?;
687 let func_type = self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?;
688 let composite_type = CompositeType {
689 inner: CompositeInnerType::Func(func_type),
690 shared,
691 };
692 return Ok(SubType {
693 is_final: true,
694 supertype: None,
695 composite_type,
696 depth: 1,
697 });
698 }
699
700 if !self.can_subtype.is_empty() && u.ratio(1, 32_u8)? {
701 self.arbitrary_sub_type_of_super_type(u)
702 } else {
703 Ok(SubType {
704 is_final: u.arbitrary()?,
705 supertype: None,
706 composite_type: self.arbitrary_composite_type(u)?,
707 depth: 1,
708 })
709 }
710 }
711
712 fn arbitrary_sub_type_of_super_type(&mut self, u: &mut Unstructured) -> Result<SubType> {
713 let supertype = *u.choose(&self.can_subtype)?;
714 let mut composite_type = self.types[usize::try_from(supertype).unwrap()]
715 .composite_type
716 .clone();
717 match &mut composite_type.inner {
718 CompositeInnerType::Array(a) => {
719 a.0 = self.arbitrary_matching_field_type(u, a.0)?;
720 }
721 CompositeInnerType::Func(f) => {
722 *f = self.arbitrary_matching_func_type(u, f)?;
723 }
724 CompositeInnerType::Struct(s) => {
725 *s = self.propagate_shared(composite_type.shared, |m| {
726 m.arbitrary_matching_struct_type(u, s)
727 })?;
728 }
729 }
730 Ok(SubType {
731 is_final: u.arbitrary()?,
732 supertype: Some(supertype),
733 composite_type,
734 depth: 1 + self.types[supertype as usize].depth,
735 })
736 }
737
738 fn arbitrary_matching_struct_type(
739 &mut self,
740 u: &mut Unstructured,
741 ty: &StructType,
742 ) -> Result<StructType> {
743 let len_extra_fields = u.int_in_range(0..=5)?;
744 let mut fields = Vec::with_capacity(ty.fields.len() + len_extra_fields);
745 for field in ty.fields.iter() {
746 fields.push(self.arbitrary_matching_field_type(u, *field)?);
747 }
748 for _ in 0..len_extra_fields {
749 fields.push(self.arbitrary_field_type(u)?);
750 }
751 Ok(StructType {
752 fields: fields.into_boxed_slice(),
753 })
754 }
755
756 fn arbitrary_matching_field_type(
757 &mut self,
758 u: &mut Unstructured,
759 ty: FieldType,
760 ) -> Result<FieldType> {
761 if ty.mutable {
762 Ok(ty)
763 } else {
764 Ok(FieldType {
765 element_type: self.arbitrary_matching_storage_type(u, ty.element_type)?,
766 mutable: false,
767 })
768 }
769 }
770
771 fn arbitrary_matching_storage_type(
772 &mut self,
773 u: &mut Unstructured,
774 ty: StorageType,
775 ) -> Result<StorageType> {
776 match ty {
777 StorageType::I8 => Ok(StorageType::I8),
778 StorageType::I16 => Ok(StorageType::I16),
779 StorageType::Val(ty) => Ok(StorageType::Val(self.arbitrary_matching_val_type(u, ty)?)),
780 }
781 }
782
783 fn arbitrary_matching_val_type(
784 &mut self,
785 u: &mut Unstructured,
786 ty: ValType,
787 ) -> Result<ValType> {
788 match ty {
789 ValType::I32 => Ok(ValType::I32),
790 ValType::I64 => Ok(ValType::I64),
791 ValType::F32 => Ok(ValType::F32),
792 ValType::F64 => Ok(ValType::F64),
793 ValType::V128 => Ok(ValType::V128),
794 ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_matching_ref_type(u, ty)?)),
795 }
796 }
797
798 fn arbitrary_matching_ref_type(&self, u: &mut Unstructured, ty: RefType) -> Result<RefType> {
799 Ok(RefType {
800 nullable: ty.nullable,
801 heap_type: self.arbitrary_matching_heap_type(u, ty.heap_type)?,
802 })
803 }
804
805 fn arbitrary_matching_heap_type(&self, u: &mut Unstructured, ty: HeapType) -> Result<HeapType> {
806 use {AbstractHeapType as AHT, CompositeInnerType as CT, HeapType as HT};
807
808 if !self.config.gc_enabled {
809 return Ok(ty);
810 }
811
812 let mut choices = vec![ty];
813 match ty {
814 HT::Abstract { shared, ty } => {
815 use AbstractHeapType::*;
816 let add_abstract = |choices: &mut Vec<HT>, tys: &[AHT]| {
817 choices.extend(tys.iter().map(|&ty| HT::Abstract { shared, ty }));
818 };
819 let add_concrete = |choices: &mut Vec<HT>, tys: &[u32]| {
820 choices.extend(
821 tys.iter()
822 .filter(|&&idx| shared == self.is_shared_type(idx))
823 .copied()
824 .map(HT::Concrete),
825 );
826 };
827 match ty {
828 Any => {
829 add_abstract(&mut choices, &[Eq, Struct, Array, I31, None]);
830 add_concrete(&mut choices, &self.array_types);
831 add_concrete(&mut choices, &self.struct_types);
832 }
833 Eq => {
834 add_abstract(&mut choices, &[Struct, Array, I31, None]);
835 add_concrete(&mut choices, &self.array_types);
836 add_concrete(&mut choices, &self.struct_types);
837 }
838 Struct => {
839 add_abstract(&mut choices, &[Struct, None]);
840 add_concrete(&mut choices, &self.struct_types);
841 }
842 Array => {
843 add_abstract(&mut choices, &[Array, None]);
844 add_concrete(&mut choices, &self.array_types);
845 }
846 I31 => {
847 add_abstract(&mut choices, &[None]);
848 }
849 Func => {
850 add_abstract(&mut choices, &[NoFunc]);
851 add_concrete(&mut choices, &self.func_types);
852 }
853 Extern => {
854 add_abstract(&mut choices, &[NoExtern]);
855 }
856 Exn | NoExn | None | NoExtern | NoFunc | Cont | NoCont => {}
857 }
858 }
859 HT::Concrete(idx) => {
860 if let Some(subs) = self.super_to_sub_types.get(&idx) {
861 choices.extend(subs.iter().copied().map(HT::Concrete));
862 }
863 match self
864 .types
865 .get(usize::try_from(idx).unwrap())
866 .map(|ty| (ty.composite_type.shared, &ty.composite_type.inner))
867 {
868 Some((shared, CT::Array(_) | CT::Struct(_))) => choices.push(HT::Abstract {
869 shared,
870 ty: AbstractHeapType::None,
871 }),
872 Some((shared, CT::Func(_))) => choices.push(HT::Abstract {
873 shared,
874 ty: AbstractHeapType::NoFunc,
875 }),
876 None => {
877 }
883 }
884 }
885 }
886 Ok(*u.choose(&choices)?)
887 }
888
889 fn arbitrary_matching_func_type(
890 &mut self,
891 u: &mut Unstructured,
892 ty: &FuncType,
893 ) -> Result<Rc<FuncType>> {
894 let mut params = Vec::with_capacity(ty.params.len());
898 for param in &ty.params {
899 params.push(self.arbitrary_super_type_of_val_type(u, *param)?);
900 }
901 let mut results = Vec::with_capacity(ty.results.len());
902 for result in &ty.results {
903 results.push(self.arbitrary_matching_val_type(u, *result)?);
904 }
905 Ok(Rc::new(FuncType { params, results }))
906 }
907
908 fn arbitrary_super_type_of_val_type(
909 &mut self,
910 u: &mut Unstructured,
911 ty: ValType,
912 ) -> Result<ValType> {
913 match ty {
914 ValType::I32 => Ok(ValType::I32),
915 ValType::I64 => Ok(ValType::I64),
916 ValType::F32 => Ok(ValType::F32),
917 ValType::F64 => Ok(ValType::F64),
918 ValType::V128 => Ok(ValType::V128),
919 ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_super_type_of_ref_type(u, ty)?)),
920 }
921 }
922
923 fn arbitrary_super_type_of_ref_type(
924 &self,
925 u: &mut Unstructured,
926 ty: RefType,
927 ) -> Result<RefType> {
928 Ok(RefType {
929 nullable: true,
936 heap_type: self.arbitrary_super_type_of_heap_type(u, ty.heap_type)?,
937 })
938 }
939
940 fn arbitrary_super_type_of_heap_type(
941 &self,
942 u: &mut Unstructured,
943 ty: HeapType,
944 ) -> Result<HeapType> {
945 use {AbstractHeapType as AHT, CompositeInnerType as CT, HeapType as HT};
946
947 if !self.config.gc_enabled {
948 return Ok(ty);
949 }
950
951 let mut choices = vec![ty];
952 match ty {
953 HT::Abstract { shared, ty } => {
954 use AbstractHeapType::*;
955 let add_abstract = |choices: &mut Vec<HT>, tys: &[AHT]| {
956 choices.extend(tys.iter().map(|&ty| HT::Abstract { shared, ty }));
957 };
958 let add_concrete = |choices: &mut Vec<HT>, tys: &[u32]| {
959 choices.extend(
960 tys.iter()
961 .filter(|&&idx| shared == self.is_shared_type(idx))
962 .copied()
963 .map(HT::Concrete),
964 );
965 };
966 match ty {
967 None => {
968 add_abstract(&mut choices, &[Any, Eq, Struct, Array, I31]);
969 add_concrete(&mut choices, &self.array_types);
970 add_concrete(&mut choices, &self.struct_types);
971 }
972 NoExtern => {
973 add_abstract(&mut choices, &[Extern]);
974 }
975 NoFunc => {
976 add_abstract(&mut choices, &[Func]);
977 add_concrete(&mut choices, &self.func_types);
978 }
979 NoExn => {
980 add_abstract(&mut choices, &[Exn]);
981 }
982 Struct | Array | I31 => {
983 add_abstract(&mut choices, &[Any, Eq]);
984 }
985 Eq => {
986 add_abstract(&mut choices, &[Any]);
987 }
988 NoCont => {
989 add_abstract(&mut choices, &[Cont]);
990 }
991 Exn | Any | Func | Extern | Cont => {}
992 }
993 }
994 HT::Concrete(mut idx) => {
995 if let Some(sub_ty) = &self.types.get(usize::try_from(idx).unwrap()) {
996 use AbstractHeapType::*;
997 let ht = |ty| HT::Abstract {
998 shared: sub_ty.composite_type.shared,
999 ty,
1000 };
1001 match &sub_ty.composite_type.inner {
1002 CT::Array(_) => {
1003 choices.extend([ht(Any), ht(Eq), ht(Array)]);
1004 }
1005 CT::Func(_) => {
1006 choices.push(ht(Func));
1007 }
1008 CT::Struct(_) => {
1009 choices.extend([ht(Any), ht(Eq), ht(Struct)]);
1010 }
1011 }
1012 } else {
1013 }
1020 while let Some(supertype) = self
1021 .types
1022 .get(usize::try_from(idx).unwrap())
1023 .and_then(|ty| ty.supertype)
1024 {
1025 choices.push(HT::Concrete(supertype));
1026 idx = supertype;
1027 }
1028 }
1029 }
1030 Ok(*u.choose(&choices)?)
1031 }
1032
1033 fn arbitrary_composite_type(&mut self, u: &mut Unstructured) -> Result<CompositeType> {
1034 use CompositeInnerType as CT;
1035 let shared = self.arbitrary_shared(u)?;
1036
1037 if !self.config.gc_enabled {
1038 return Ok(CompositeType {
1039 shared,
1040 inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?),
1041 });
1042 }
1043
1044 match u.int_in_range(0..=2)? {
1045 0 => Ok(CompositeType {
1046 shared,
1047 inner: CT::Array(ArrayType(
1048 self.propagate_shared(shared, |m| m.arbitrary_field_type(u))?,
1049 )),
1050 }),
1051 1 => Ok(CompositeType {
1052 shared,
1053 inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?),
1054 }),
1055 2 => Ok(CompositeType {
1056 shared,
1057 inner: CT::Struct(self.propagate_shared(shared, |m| m.arbitrary_struct_type(u))?),
1058 }),
1059 _ => unreachable!(),
1060 }
1061 }
1062
1063 fn arbitrary_struct_type(&mut self, u: &mut Unstructured) -> Result<StructType> {
1064 let len = u.int_in_range(0..=20)?;
1065 let mut fields = Vec::with_capacity(len);
1066 for _ in 0..len {
1067 fields.push(self.arbitrary_field_type(u)?);
1068 }
1069 Ok(StructType {
1070 fields: fields.into_boxed_slice(),
1071 })
1072 }
1073
1074 fn arbitrary_field_type(&mut self, u: &mut Unstructured) -> Result<FieldType> {
1075 Ok(FieldType {
1076 element_type: self.arbitrary_storage_type(u)?,
1077 mutable: u.arbitrary()?,
1078 })
1079 }
1080
1081 fn arbitrary_storage_type(&mut self, u: &mut Unstructured) -> Result<StorageType> {
1082 match u.int_in_range(0..=2)? {
1083 0 => Ok(StorageType::I8),
1084 1 => Ok(StorageType::I16),
1085 2 => Ok(StorageType::Val(self.arbitrary_valtype(u)?)),
1086 _ => unreachable!(),
1087 }
1088 }
1089
1090 fn arbitrary_ref_type(&self, u: &mut Unstructured) -> Result<RefType> {
1091 if !self.config.reference_types_enabled {
1092 return Ok(RefType::FUNCREF);
1093 }
1094 Ok(RefType {
1095 nullable: true,
1096 heap_type: self.arbitrary_heap_type(u)?,
1097 })
1098 }
1099
1100 fn arbitrary_heap_type(&self, u: &mut Unstructured) -> Result<HeapType> {
1101 assert!(self.config.reference_types_enabled);
1102
1103 let concrete_type_limit = match self.max_type_limit {
1104 MaxTypeLimit::Num(n) => n,
1105 MaxTypeLimit::ModuleTypes => u32::try_from(self.types.len()).unwrap(),
1106 };
1107
1108 if self.config.gc_enabled && concrete_type_limit > 0 && u.arbitrary()? {
1109 let idx = u.int_in_range(0..=concrete_type_limit - 1)?;
1110 if let Some(ty) = self.types.get(idx as usize) {
1116 if !(self.must_share && !ty.composite_type.shared) {
1119 return Ok(HeapType::Concrete(idx));
1120 }
1121 }
1122 }
1123
1124 use AbstractHeapType::*;
1125 let mut choices = vec![Func, Extern];
1126 if self.config.exceptions_enabled {
1127 choices.push(Exn);
1128 }
1129 if self.config.gc_enabled {
1130 choices.extend(
1131 [Any, None, NoExtern, NoFunc, Eq, Struct, Array, I31]
1132 .iter()
1133 .copied(),
1134 );
1135 }
1136
1137 Ok(HeapType::Abstract {
1138 shared: self.arbitrary_shared(u)?,
1139 ty: *u.choose(&choices)?,
1140 })
1141 }
1142
1143 fn arbitrary_func_type(&mut self, u: &mut Unstructured) -> Result<Rc<FuncType>> {
1144 let mut params = vec![];
1145 let mut results = vec![];
1146 let max_params = 20;
1147 arbitrary_loop(u, 0, max_params, |u| {
1148 params.push(self.arbitrary_valtype(u)?);
1149 Ok(true)
1150 })?;
1151 let max_results = if self.config.multi_value_enabled {
1152 max_params
1153 } else {
1154 1
1155 };
1156 arbitrary_loop(u, 0, max_results, |u| {
1157 results.push(self.arbitrary_valtype(u)?);
1158 Ok(true)
1159 })?;
1160 Ok(Rc::new(FuncType { params, results }))
1161 }
1162
1163 fn can_add_local_or_import_tag(&self) -> bool {
1164 self.config.exceptions_enabled
1165 && self.has_tag_func_types()
1166 && self.tags.len() < self.config.max_tags
1167 }
1168
1169 fn can_add_local_or_import_func(&self) -> bool {
1170 !self.func_types.is_empty() && self.funcs.len() < self.config.max_funcs
1171 }
1172
1173 fn can_add_local_or_import_table(&self) -> bool {
1174 self.tables.len() < self.config.max_tables
1175 }
1176
1177 fn can_add_local_or_import_global(&self) -> bool {
1178 self.globals.len() < self.config.max_globals
1179 }
1180
1181 fn can_add_local_or_import_memory(&self) -> bool {
1182 self.memories.len() < self.config.max_memories
1183 }
1184
1185 fn arbitrary_imports(&mut self, u: &mut Unstructured) -> Result<()> {
1186 if self.config.max_type_size < self.type_size {
1187 return Ok(());
1188 }
1189
1190 let mut import_strings = HashSet::new();
1191 let mut choices: Vec<fn(&mut Unstructured, &mut Module) -> Result<EntityType>> =
1192 Vec::with_capacity(5);
1193 let min = self.config.min_imports.saturating_sub(self.num_imports);
1194 let max = self.config.max_imports.saturating_sub(self.num_imports);
1195 arbitrary_loop(u, min, max, |u| {
1196 choices.clear();
1197 if self.can_add_local_or_import_tag() {
1198 choices.push(|u, m| {
1199 let ty = m.arbitrary_tag_type(u)?;
1200 Ok(EntityType::Tag(ty))
1201 });
1202 }
1203 if self.can_add_local_or_import_func() {
1204 choices.push(|u, m| {
1205 let idx = *u.choose(&m.func_types)?;
1206 let ty = m.func_type(idx).clone();
1207 Ok(EntityType::Func(idx, ty))
1208 });
1209 }
1210 if self.can_add_local_or_import_global() {
1211 choices.push(|u, m| {
1212 let ty = m.arbitrary_global_type(u)?;
1213 Ok(EntityType::Global(ty))
1214 });
1215 }
1216 if self.can_add_local_or_import_memory() {
1217 choices.push(|u, m| {
1218 let ty = arbitrary_memtype(u, m.config())?;
1219 Ok(EntityType::Memory(ty))
1220 });
1221 }
1222 if self.can_add_local_or_import_table() {
1223 choices.push(|u, m| {
1224 let ty = arbitrary_table_type(u, m.config(), Some(m))?;
1225 Ok(EntityType::Table(ty))
1226 });
1227 }
1228
1229 if choices.is_empty() {
1230 return Ok(false);
1235 }
1236
1237 let f = u.choose(&choices)?;
1240 let entity_type = f(u, self)?;
1241 let budget = self.config.max_type_size - self.type_size;
1242 if entity_type.size() + 1 > budget {
1243 return Ok(false);
1244 }
1245 self.type_size += entity_type.size() + 1;
1246
1247 let mut import_pair = unique_import_strings(1_000, u)?;
1249 if self.duplicate_imports_behavior == DuplicateImportsBehavior::Disallowed {
1250 while import_strings.contains(&import_pair) {
1251 use std::fmt::Write;
1252 write!(&mut import_pair.1, "{}", import_strings.len()).unwrap();
1253 }
1254 import_strings.insert(import_pair.clone());
1255 }
1256 let (module, field) = import_pair;
1257
1258 match &entity_type {
1261 EntityType::Tag(ty) => self.tags.push(ty.clone()),
1262 EntityType::Func(idx, ty) => self.funcs.push((*idx, ty.clone())),
1263 EntityType::Global(ty) => self.globals.push(*ty),
1264 EntityType::Table(ty) => self.tables.push(*ty),
1265 EntityType::Memory(ty) => self.memories.push(*ty),
1266 }
1267
1268 self.num_imports += 1;
1269 self.imports.push(Import {
1270 module,
1271 field,
1272 entity_type,
1273 });
1274 Ok(true)
1275 })?;
1276
1277 Ok(())
1278 }
1279
1280 fn arbitrary_imports_from_available(&mut self, u: &mut Unstructured) -> Result<bool> {
1286 let example_module = if let Some(wasm) = self.config.available_imports.take() {
1287 wasm
1288 } else {
1289 return Ok(false);
1290 };
1291
1292 #[cfg(feature = "wasmparser")]
1293 {
1294 self._arbitrary_imports_from_available(u, &example_module)?;
1295 Ok(true)
1296 }
1297 #[cfg(not(feature = "wasmparser"))]
1298 {
1299 let _ = (example_module, u);
1300 panic!("support for `available_imports` was disabled at compile time");
1301 }
1302 }
1303
1304 #[cfg(feature = "wasmparser")]
1305 fn _arbitrary_imports_from_available(
1306 &mut self,
1307 u: &mut Unstructured,
1308 example_module: &[u8],
1309 ) -> Result<()> {
1310 let mut available_types = Vec::new();
1318 let mut available_imports = Vec::<wasmparser::Import>::new();
1319 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
1320 match payload.expect("could not parse the available import payload") {
1321 wasmparser::Payload::TypeSection(type_reader) => {
1322 for ty in type_reader.into_iter_err_on_gc_types() {
1323 let ty = ty.expect("could not parse type section");
1324 available_types.push((ty, None));
1325 }
1326 }
1327 wasmparser::Payload::ImportSection(import_reader) => {
1328 for im in import_reader {
1329 let im = im.expect("could not read import");
1330 let use_import = u.arbitrary().unwrap_or(false);
1333 if !use_import {
1334 continue;
1335 }
1336 available_imports.push(im);
1337 }
1338 }
1339 _ => {}
1340 }
1341 }
1342
1343 let max_types = self.config.max_types;
1346 let multi_value_enabled = self.config.multi_value_enabled;
1347 let mut new_imports = Vec::with_capacity(available_imports.len());
1348 let first_type_index = self.types.len();
1349 let mut new_types = Vec::<SubType>::new();
1350
1351 let mut make_func_type = |module: &Self, parsed_sig_idx: u32| {
1354 let serialized_sig_idx = match available_types.get_mut(parsed_sig_idx as usize) {
1355 None => panic!("signature index refers to a type out of bounds"),
1356 Some((_, Some(idx))) => *idx as usize,
1357 Some((func_type, index_store)) => {
1358 let multi_value_required = func_type.results().len() > 1;
1359 let new_index = first_type_index + new_types.len();
1360 if new_index >= max_types || (multi_value_required && !multi_value_enabled) {
1361 return None;
1362 }
1363 let func_type = Rc::new(FuncType {
1364 params: func_type
1365 .params()
1366 .iter()
1367 .map(|t| (*t).try_into().unwrap())
1368 .collect(),
1369 results: func_type
1370 .results()
1371 .iter()
1372 .map(|t| (*t).try_into().unwrap())
1373 .collect(),
1374 });
1375 index_store.replace(new_index as u32);
1376 let shared = module.arbitrary_shared(u).ok()?;
1377 new_types.push(SubType {
1378 is_final: true,
1379 supertype: None,
1380 composite_type: CompositeType::new_func(Rc::clone(&func_type), shared),
1381 depth: 1,
1382 });
1383 new_index
1384 }
1385 };
1386 match &new_types[serialized_sig_idx - first_type_index]
1387 .composite_type
1388 .inner
1389 {
1390 CompositeInnerType::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))),
1391 _ => unimplemented!(),
1392 }
1393 };
1394
1395 for import in available_imports {
1396 let type_size_budget = self.config.max_type_size - self.type_size;
1397 let entity_type = match &import.ty {
1398 wasmparser::TypeRef::Func(sig_idx) => {
1399 if self.funcs.len() >= self.config.max_funcs {
1400 continue;
1401 } else if let Some((sig_idx, func_type)) = make_func_type(&self, *sig_idx) {
1402 let entity = EntityType::Func(sig_idx as u32, Rc::clone(&func_type));
1403 if type_size_budget < entity.size() {
1404 continue;
1405 }
1406 self.funcs.push((sig_idx, func_type));
1407 entity
1408 } else {
1409 continue;
1410 }
1411 }
1412
1413 wasmparser::TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }) => {
1414 let can_add_tag = self.tags.len() < self.config.max_tags;
1415 if !self.config.exceptions_enabled || !can_add_tag {
1416 continue;
1417 } else if let Some((sig_idx, func_type)) = make_func_type(&self, *func_type_idx)
1418 {
1419 let tag_type = TagType {
1420 func_type_idx: sig_idx,
1421 func_type,
1422 };
1423 let entity = EntityType::Tag(tag_type.clone());
1424 if type_size_budget < entity.size() {
1425 continue;
1426 }
1427 self.tags.push(tag_type);
1428 entity
1429 } else {
1430 continue;
1431 }
1432 }
1433
1434 wasmparser::TypeRef::Table(table_ty) => {
1435 let table_ty = TableType::try_from(*table_ty).unwrap();
1436 let entity = EntityType::Table(table_ty);
1437 let type_size = entity.size();
1438 if type_size_budget < type_size || !self.can_add_local_or_import_table() {
1439 continue;
1440 }
1441 self.type_size += type_size;
1442 self.tables.push(table_ty);
1443 entity
1444 }
1445
1446 wasmparser::TypeRef::Memory(memory_ty) => {
1447 let memory_ty = MemoryType::try_from(*memory_ty).unwrap();
1448 let entity = EntityType::Memory(memory_ty);
1449 let type_size = entity.size();
1450 if type_size_budget < type_size || !self.can_add_local_or_import_memory() {
1451 continue;
1452 }
1453 self.type_size += type_size;
1454 self.memories.push(memory_ty);
1455 entity
1456 }
1457
1458 wasmparser::TypeRef::Global(global_ty) => {
1459 let global_ty = (*global_ty).try_into().unwrap();
1460 let entity = EntityType::Global(global_ty);
1461 let type_size = entity.size();
1462 if type_size_budget < type_size || !self.can_add_local_or_import_global() {
1463 continue;
1464 }
1465 self.type_size += type_size;
1466 self.globals.push(global_ty);
1467 entity
1468 }
1469 };
1470 new_imports.push(Import {
1471 module: import.module.to_string(),
1472 field: import.name.to_string(),
1473 entity_type,
1474 });
1475 self.num_imports += 1;
1476 }
1477
1478 for ty in new_types {
1480 self.rec_groups.push(self.types.len()..self.types.len() + 1);
1481 self.add_type(ty);
1482 }
1483 self.imports.extend(new_imports);
1484
1485 Ok(())
1486 }
1487
1488 fn type_of(&self, kind: ExportKind, index: u32) -> EntityType {
1489 match kind {
1490 ExportKind::Global => EntityType::Global(self.globals[index as usize]),
1491 ExportKind::Memory => EntityType::Memory(self.memories[index as usize]),
1492 ExportKind::Table => EntityType::Table(self.tables[index as usize]),
1493 ExportKind::Func => {
1494 let (_idx, ty) = &self.funcs[index as usize];
1495 EntityType::Func(u32::max_value(), ty.clone())
1496 }
1497 ExportKind::Tag => EntityType::Tag(self.tags[index as usize].clone()),
1498 }
1499 }
1500
1501 fn ty(&self, idx: u32) -> &SubType {
1502 &self.types[idx as usize]
1503 }
1504
1505 fn func_types(&self) -> impl Iterator<Item = (u32, &FuncType)> + '_ {
1506 self.func_types
1507 .iter()
1508 .copied()
1509 .map(move |type_i| (type_i, &**self.func_type(type_i)))
1510 }
1511
1512 fn func_type(&self, idx: u32) -> &Rc<FuncType> {
1513 match &self.ty(idx).composite_type.inner {
1514 CompositeInnerType::Func(f) => f,
1515 _ => panic!("types[{idx}] is not a func type"),
1516 }
1517 }
1518
1519 fn tags(&self) -> impl Iterator<Item = (u32, &TagType)> + '_ {
1520 self.tags
1521 .iter()
1522 .enumerate()
1523 .map(move |(i, ty)| (i as u32, ty))
1524 }
1525
1526 fn funcs(&self) -> impl Iterator<Item = (u32, &Rc<FuncType>)> + '_ {
1527 self.funcs
1528 .iter()
1529 .enumerate()
1530 .map(move |(i, (_, ty))| (i as u32, ty))
1531 }
1532
1533 fn has_tag_func_types(&self) -> bool {
1534 self.tag_func_types().next().is_some()
1535 }
1536
1537 fn tag_func_types(&self) -> impl Iterator<Item = u32> + '_ {
1538 self.func_types
1539 .iter()
1540 .copied()
1541 .filter(move |i| self.func_type(*i).results.is_empty())
1542 }
1543
1544 fn arbitrary_valtype(&self, u: &mut Unstructured) -> Result<ValType> {
1545 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1546 enum ValTypeClass {
1547 I32,
1548 I64,
1549 F32,
1550 F64,
1551 V128,
1552 Ref,
1553 }
1554
1555 let mut val_classes: Vec<_> = self
1556 .valtypes
1557 .iter()
1558 .map(|vt| match vt {
1559 ValType::I32 => ValTypeClass::I32,
1560 ValType::I64 => ValTypeClass::I64,
1561 ValType::F32 => ValTypeClass::F32,
1562 ValType::F64 => ValTypeClass::F64,
1563 ValType::V128 => ValTypeClass::V128,
1564 ValType::Ref(_) => ValTypeClass::Ref,
1565 })
1566 .collect();
1567 val_classes.sort_unstable();
1568 val_classes.dedup();
1569
1570 match u.choose(&val_classes)? {
1571 ValTypeClass::I32 => Ok(ValType::I32),
1572 ValTypeClass::I64 => Ok(ValType::I64),
1573 ValTypeClass::F32 => Ok(ValType::F32),
1574 ValTypeClass::F64 => Ok(ValType::F64),
1575 ValTypeClass::V128 => Ok(ValType::V128),
1576 ValTypeClass::Ref => Ok(ValType::Ref(self.arbitrary_ref_type(u)?)),
1577 }
1578 }
1579
1580 fn arbitrary_global_type(&self, u: &mut Unstructured) -> Result<GlobalType> {
1581 let val_type = self.arbitrary_valtype(u)?;
1582 let shared = match val_type {
1584 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {
1585 self.arbitrary_shared(u)?
1586 }
1587 ValType::Ref(r) => self.is_shared_ref_type(r),
1588 };
1589 Ok(GlobalType {
1590 val_type,
1591 mutable: u.arbitrary()?,
1592 shared,
1593 })
1594 }
1595
1596 fn arbitrary_tag_type(&self, u: &mut Unstructured) -> Result<TagType> {
1597 let candidate_func_types: Vec<_> = self.tag_func_types().collect();
1598 arbitrary_tag_type(u, &candidate_func_types, |ty_idx| {
1599 self.func_type(ty_idx).clone()
1600 })
1601 }
1602
1603 fn arbitrary_tags(&mut self, u: &mut Unstructured) -> Result<()> {
1604 if !self.config.exceptions_enabled || !self.has_tag_func_types() {
1605 return Ok(());
1606 }
1607
1608 arbitrary_loop(u, self.config.min_tags, self.config.max_tags, |u| {
1609 if !self.can_add_local_or_import_tag() {
1610 return Ok(false);
1611 }
1612 self.tags.push(self.arbitrary_tag_type(u)?);
1613 self.num_defined_tags += 1;
1614 Ok(true)
1615 })
1616 }
1617
1618 fn arbitrary_funcs(&mut self, u: &mut Unstructured) -> Result<()> {
1619 if self.func_types.is_empty() {
1620 return Ok(());
1621 }
1622
1623 let unshared_func_types: Vec<_> = self
1628 .func_types
1629 .iter()
1630 .copied()
1631 .filter(|&i| !self.is_shared_type(i))
1632 .collect();
1633 if unshared_func_types.is_empty() {
1634 return Ok(());
1635 }
1636
1637 arbitrary_loop(u, self.config.min_funcs, self.config.max_funcs, |u| {
1638 if !self.can_add_local_or_import_func() {
1639 return Ok(false);
1640 }
1641 let max = unshared_func_types.len() - 1;
1642 let ty = unshared_func_types[u.int_in_range(0..=max)?];
1643 self.funcs.push((ty, self.func_type(ty).clone()));
1644 self.num_defined_funcs += 1;
1645 Ok(true)
1646 })
1647 }
1648
1649 fn arbitrary_tables(&mut self, u: &mut Unstructured) -> Result<()> {
1650 arbitrary_loop(
1651 u,
1652 self.config.min_tables as usize,
1653 self.config.max_tables as usize,
1654 |u| {
1655 if !self.can_add_local_or_import_table() {
1656 return Ok(false);
1657 }
1658 let ty = arbitrary_table_type(u, self.config(), Some(self))?;
1659 let init = self.arbitrary_table_init(u, ty.element_type)?;
1660 self.defined_tables.push(init);
1661 self.tables.push(ty);
1662 Ok(true)
1663 },
1664 )
1665 }
1666
1667 fn arbitrary_table_init(
1673 &mut self,
1674 u: &mut Unstructured,
1675 ty: RefType,
1676 ) -> Result<Option<ConstExpr>> {
1677 if !self.config.gc_enabled {
1678 assert!(ty.nullable);
1679 return Ok(None);
1680 }
1681 if ty.nullable && u.arbitrary()? {
1684 return Ok(None);
1685 }
1686 let expr = self.arbitrary_const_expr(ValType::Ref(ty), u)?;
1687 Ok(Some(expr))
1688 }
1689
1690 fn arbitrary_memories(&mut self, u: &mut Unstructured) -> Result<()> {
1691 arbitrary_loop(
1692 u,
1693 self.config.min_memories as usize,
1694 self.config.max_memories as usize,
1695 |u| {
1696 if !self.can_add_local_or_import_memory() {
1697 return Ok(false);
1698 }
1699 self.num_defined_memories += 1;
1700 self.memories.push(arbitrary_memtype(u, self.config())?);
1701 Ok(true)
1702 },
1703 )
1704 }
1705
1706 fn add_arbitrary_global_of_type(
1708 &mut self,
1709 ty: GlobalType,
1710 u: &mut Unstructured,
1711 ) -> Result<u32> {
1712 let expr = self.arbitrary_const_expr(ty.val_type, u)?;
1713 let global_idx = self.globals.len() as u32;
1714 self.globals.push(ty);
1715 self.defined_globals.push((global_idx, expr));
1716 Ok(global_idx)
1717 }
1718
1719 fn arbitrary_const_expr(&mut self, ty: ValType, u: &mut Unstructured) -> Result<ConstExpr> {
1721 let mut choices = mem::take(&mut self.const_expr_choices);
1722 choices.clear();
1723
1724 for i in self.globals_for_const_expr(ty) {
1728 choices.push(Box::new(move |_, _| Ok(ConstExpr::global_get(i))));
1729 }
1730
1731 let ty = self.arbitrary_matching_val_type(u, ty)?;
1735 match ty {
1736 ValType::I32 => {
1737 choices.push(Box::new(|u, _| Ok(ConstExpr::i32_const(u.arbitrary()?))));
1738 if self.config.extended_const_enabled {
1739 choices.push(Box::new(arbitrary_extended_const));
1740 }
1741 }
1742 ValType::I64 => {
1743 choices.push(Box::new(|u, _| Ok(ConstExpr::i64_const(u.arbitrary()?))));
1744 if self.config.extended_const_enabled {
1745 choices.push(Box::new(arbitrary_extended_const));
1746 }
1747 }
1748 ValType::F32 => choices.push(Box::new(|u, _| Ok(ConstExpr::f32_const(u.arbitrary()?)))),
1749 ValType::F64 => choices.push(Box::new(|u, _| Ok(ConstExpr::f64_const(u.arbitrary()?)))),
1750 ValType::V128 => {
1751 choices.push(Box::new(|u, _| Ok(ConstExpr::v128_const(u.arbitrary()?))))
1752 }
1753
1754 ValType::Ref(ty) => {
1755 if ty.nullable {
1756 choices.push(Box::new(move |_, _| Ok(ConstExpr::ref_null(ty.heap_type))));
1757 }
1758
1759 match ty.heap_type {
1760 HeapType::Abstract {
1761 ty: AbstractHeapType::Func,
1762 shared,
1763 } => {
1764 let num_funcs = self
1765 .funcs
1766 .iter()
1767 .filter(|(t, _)| shared == self.is_shared_type(*t))
1768 .count();
1769 if num_funcs > 0 {
1770 let pick = u.int_in_range(0..=num_funcs - 1)?;
1771 let (i, _) = self
1772 .funcs
1773 .iter()
1774 .map(|(t, _)| *t)
1775 .enumerate()
1776 .filter(|(_, t)| shared == self.is_shared_type(*t))
1777 .nth(pick)
1778 .unwrap();
1779 choices.push(Box::new(move |_, _| Ok(ConstExpr::ref_func(i as u32))));
1780 }
1781 }
1782
1783 HeapType::Concrete(ty) => {
1784 for (i, fty) in self.funcs.iter().map(|(t, _)| *t).enumerate() {
1785 if ty != fty {
1786 continue;
1787 }
1788 choices.push(Box::new(move |_, _| Ok(ConstExpr::ref_func(i as u32))));
1789 }
1790 }
1791
1792 _ => {}
1795 }
1796 }
1797 }
1798
1799 let f = u.choose(&choices)?;
1800 let ret = f(u, ty);
1801 self.const_expr_choices = choices;
1802 return ret;
1803
1804 fn arbitrary_extended_const(u: &mut Unstructured<'_>, ty: ValType) -> Result<ConstExpr> {
1812 use wasm_encoder::Instruction::*;
1813
1814 assert!(ty == ValType::I32 || ty == ValType::I64);
1817 let add = if ty == ValType::I32 { I32Add } else { I64Add };
1818 let sub = if ty == ValType::I32 { I32Sub } else { I64Sub };
1819 let mul = if ty == ValType::I32 { I32Mul } else { I64Mul };
1820 let const_: fn(&mut Unstructured<'_>) -> Result<wasm_encoder::Instruction<'static>> =
1821 if ty == ValType::I32 {
1822 |u| u.arbitrary().map(I32Const)
1823 } else {
1824 |u| u.arbitrary().map(I64Const)
1825 };
1826
1827 let mut instrs = Vec::new();
1832 let mut needed = 1;
1833 while needed > 0 {
1834 let choice = if u.is_empty() || instrs.len() > 10 {
1838 0
1839 } else {
1840 u.int_in_range(0..=3)?
1841 };
1842 match choice {
1843 0 => {
1844 instrs.push(const_(u)?);
1845 needed -= 1;
1846 }
1847 1 => {
1848 instrs.push(add.clone());
1849 needed += 1;
1850 }
1851 2 => {
1852 instrs.push(sub.clone());
1853 needed += 1;
1854 }
1855 3 => {
1856 instrs.push(mul.clone());
1857 needed += 1;
1858 }
1859 _ => unreachable!(),
1860 }
1861 }
1862 Ok(ConstExpr::extended(instrs.into_iter().rev()))
1863 }
1864 }
1865
1866 fn arbitrary_globals(&mut self, u: &mut Unstructured) -> Result<()> {
1867 arbitrary_loop(u, self.config.min_globals, self.config.max_globals, |u| {
1868 if !self.can_add_local_or_import_global() {
1869 return Ok(false);
1870 }
1871
1872 let ty = self.arbitrary_global_type(u)?;
1873 self.add_arbitrary_global_of_type(ty, u)?;
1874
1875 Ok(true)
1876 })
1877 }
1878
1879 fn required_exports(&mut self, u: &mut Unstructured) -> Result<bool> {
1880 let example_module = if let Some(wasm) = self.config.exports.clone() {
1881 wasm
1882 } else {
1883 return Ok(false);
1884 };
1885
1886 #[cfg(feature = "wasmparser")]
1887 {
1888 self._required_exports(u, &example_module)?;
1889 Ok(true)
1890 }
1891 #[cfg(not(feature = "wasmparser"))]
1892 {
1893 let _ = (example_module, u);
1894 panic!("support for `exports` was disabled at compile time");
1895 }
1896 }
1897
1898 #[cfg(feature = "wasmparser")]
1899 fn _required_exports(&mut self, u: &mut Unstructured, example_module: &[u8]) -> Result<()> {
1900 let mut required_exports: Vec<wasmparser::Export> = vec![];
1901 let mut validator = wasmparser::Validator::new();
1902 let exports_types = validator
1903 .validate_all(&example_module)
1904 .expect("Failed to validate `exports` Wasm");
1905 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
1906 match payload.expect("Failed to read `exports` Wasm") {
1907 wasmparser::Payload::ExportSection(export_reader) => {
1908 required_exports = export_reader
1909 .into_iter()
1910 .collect::<Result<_, _>>()
1911 .expect("Failed to read `exports` export section");
1912 }
1913 _ => {}
1914 }
1915 }
1916
1917 let exports_types = exports_types.as_ref();
1919 for export in required_exports {
1920 let new_index = match exports_types
1921 .entity_type_from_export(&export)
1922 .unwrap_or_else(|| {
1923 panic!(
1924 "Unable to get type from export {:?} in `exports` Wasm",
1925 export,
1926 )
1927 }) {
1928 wasmparser::types::EntityType::Func(id) => {
1930 let subtype = exports_types.get(id).unwrap_or_else(|| {
1931 panic!(
1932 "Unable to get subtype for function {:?} in `exports` Wasm",
1933 id
1934 )
1935 });
1936 match &subtype.composite_type.inner {
1937 wasmparser::CompositeInnerType::Func(func_type) => {
1938 assert!(
1939 subtype.is_final,
1940 "Subtype {:?} from `exports` Wasm is not final",
1941 subtype
1942 );
1943 assert!(
1944 subtype.supertype_idx.is_none(),
1945 "Subtype {:?} from `exports` Wasm has non-empty supertype",
1946 subtype
1947 );
1948 let new_type = Rc::new(FuncType {
1949 params: func_type
1950 .params()
1951 .iter()
1952 .copied()
1953 .map(|t| t.try_into().unwrap())
1954 .collect(),
1955 results: func_type
1956 .results()
1957 .iter()
1958 .copied()
1959 .map(|t| t.try_into().unwrap())
1960 .collect(),
1961 });
1962 self.rec_groups.push(self.types.len()..self.types.len() + 1);
1963 let type_index = self.add_type(SubType {
1964 is_final: true,
1965 supertype: None,
1966 depth: 1,
1967 composite_type: CompositeType::new_func(
1968 Rc::clone(&new_type),
1969 subtype.composite_type.shared,
1970 ),
1971 });
1972 let func_index = self.funcs.len() as u32;
1973 self.funcs.push((type_index, new_type));
1974 self.num_defined_funcs += 1;
1975 func_index
1976 }
1977 _ => panic!(
1978 "Unable to handle type {:?} from `exports` Wasm",
1979 subtype.composite_type
1980 ),
1981 }
1982 }
1983 wasmparser::types::EntityType::Global(global_type) => {
1985 self.add_arbitrary_global_of_type(global_type.try_into().unwrap(), u)?
1986 }
1987 wasmparser::types::EntityType::Table(_)
1988 | wasmparser::types::EntityType::Memory(_)
1989 | wasmparser::types::EntityType::Tag(_) => {
1990 panic!(
1991 "Config `exports` has an export of type {:?} which cannot yet be handled.",
1992 export.kind
1993 )
1994 }
1995 };
1996 self.exports
1997 .push((export.name.to_string(), export.kind.into(), new_index));
1998 self.export_names.insert(export.name.to_string());
1999 }
2000
2001 Ok(())
2002 }
2003
2004 fn arbitrary_exports(&mut self, u: &mut Unstructured) -> Result<()> {
2005 if self.config.max_type_size < self.type_size && !self.config.export_everything {
2006 return Ok(());
2007 }
2008
2009 let mut choices: Vec<Vec<(ExportKind, u32)>> = Vec::with_capacity(6);
2011 choices.push(
2012 (0..self.funcs.len())
2013 .map(|i| (ExportKind::Func, i as u32))
2014 .collect(),
2015 );
2016 choices.push(
2017 (0..self.tables.len())
2018 .map(|i| (ExportKind::Table, i as u32))
2019 .collect(),
2020 );
2021 choices.push(
2022 (0..self.memories.len())
2023 .map(|i| (ExportKind::Memory, i as u32))
2024 .collect(),
2025 );
2026 choices.push(
2027 (0..self.globals.len())
2028 .map(|i| (ExportKind::Global, i as u32))
2029 .collect(),
2030 );
2031
2032 if self.config.export_everything {
2035 for choices_by_kind in choices {
2036 for (kind, idx) in choices_by_kind {
2037 let name = unique_string(1_000, &mut self.export_names, u)?;
2038 self.add_arbitrary_export(name, kind, idx)?;
2039 }
2040 }
2041 return Ok(());
2042 }
2043
2044 arbitrary_loop(u, self.config.min_exports, self.config.max_exports, |u| {
2045 let max_size = self.config.max_type_size - self.type_size;
2051 for list in choices.iter_mut() {
2052 list.retain(|(kind, idx)| self.type_of(*kind, *idx).size() + 1 < max_size);
2053 }
2054 choices.retain(|list| !list.is_empty());
2055 if choices.is_empty() {
2056 return Ok(false);
2057 }
2058
2059 let name = unique_string(1_000, &mut self.export_names, u)?;
2062 let list = u.choose(&choices)?;
2063 let (kind, idx) = *u.choose(list)?;
2064 self.add_arbitrary_export(name, kind, idx)?;
2065 Ok(true)
2066 })
2067 }
2068
2069 fn add_arbitrary_export(&mut self, name: String, kind: ExportKind, idx: u32) -> Result<()> {
2070 let ty = self.type_of(kind, idx);
2071 self.type_size += 1 + ty.size();
2072 if self.type_size <= self.config.max_type_size {
2073 self.exports.push((name, kind, idx));
2074 Ok(())
2075 } else {
2076 Err(arbitrary::Error::IncorrectFormat)
2080 }
2081 }
2082
2083 fn arbitrary_start(&mut self, u: &mut Unstructured) -> Result<()> {
2084 if !self.config.allow_start_export {
2085 return Ok(());
2086 }
2087
2088 let mut choices = Vec::with_capacity(self.funcs.len() as usize);
2089
2090 for (func_idx, ty) in self.funcs() {
2091 if ty.params.is_empty() && ty.results.is_empty() {
2092 choices.push(func_idx);
2093 }
2094 }
2095
2096 if !choices.is_empty() && u.arbitrary().unwrap_or(false) {
2097 let f = *u.choose(&choices)?;
2098 self.start = Some(f);
2099 }
2100
2101 Ok(())
2102 }
2103
2104 fn arbitrary_elems(&mut self, u: &mut Unstructured) -> Result<()> {
2105 let mut global_i32 = vec![];
2107 let mut global_i64 = vec![];
2108 if !self.config.disallow_traps {
2109 for i in self.globals_for_const_expr(ValType::I32) {
2110 global_i32.push(i);
2111 }
2112 for i in self.globals_for_const_expr(ValType::I64) {
2113 global_i64.push(i);
2114 }
2115 }
2116 let disallow_traps = self.config.disallow_traps;
2117 let arbitrary_active_elem =
2118 |u: &mut Unstructured, min_mem_size: u64, table: Option<u32>, table_ty: &TableType| {
2119 let global_choices = if table_ty.table64 {
2120 &global_i64
2121 } else {
2122 &global_i32
2123 };
2124 let (offset, max_size_hint) = if !global_choices.is_empty() && u.arbitrary()? {
2125 let g = u.choose(&global_choices)?;
2126 (Offset::Global(*g), None)
2127 } else {
2128 let max_mem_size = if disallow_traps {
2129 table_ty.minimum
2130 } else if table_ty.table64 {
2131 u64::MAX
2132 } else {
2133 u64::from(u32::MAX)
2134 };
2135 let offset = arbitrary_offset(u, min_mem_size, max_mem_size, 0)?;
2136 let max_size_hint = if disallow_traps
2137 || (offset <= min_mem_size
2138 && u.int_in_range(0..=CHANCE_OFFSET_INBOUNDS)? != 0)
2139 {
2140 Some(min_mem_size - offset)
2141 } else {
2142 None
2143 };
2144
2145 let offset = if table_ty.table64 {
2146 Offset::Const64(offset as i64)
2147 } else {
2148 Offset::Const32(offset as i32)
2149 };
2150 (offset, max_size_hint)
2151 };
2152 Ok((ElementKind::Active { table, offset }, max_size_hint))
2153 };
2154
2155 type GenElemSegment<'a> =
2159 dyn Fn(&mut Unstructured) -> Result<(ElementKind, Option<u64>)> + 'a;
2160 let mut choices: Vec<Box<GenElemSegment>> = Vec::new();
2161
2162 if self.config.bulk_memory_enabled {
2165 choices.push(Box::new(|_| Ok((ElementKind::Passive, None))));
2166 choices.push(Box::new(|_| Ok((ElementKind::Declared, None))));
2167 }
2168
2169 for (i, ty) in self.tables.iter().enumerate() {
2170 if ty.minimum == 0 && u.int_in_range(0..=CHANCE_SEGMENT_ON_EMPTY)? != 0 {
2175 continue;
2176 }
2177
2178 let minimum = ty.minimum;
2179 let ty = *ty;
2182 if i == 0 && ty.element_type == RefType::FUNCREF {
2183 choices.push(Box::new(move |u| {
2184 arbitrary_active_elem(u, minimum, None, &ty)
2185 }));
2186 }
2187 if self.config.bulk_memory_enabled {
2188 let idx = Some(i as u32);
2189 choices.push(Box::new(move |u| {
2190 arbitrary_active_elem(u, minimum, idx, &ty)
2191 }));
2192 }
2193 }
2194
2195 if choices.is_empty() {
2196 return Ok(());
2197 }
2198
2199 arbitrary_loop(
2200 u,
2201 self.config.min_element_segments,
2202 self.config.max_element_segments,
2203 |u| {
2204 let (kind, max_size_hint) = u.choose(&choices)?(u)?;
2207 let max = max_size_hint
2208 .map(|i| usize::try_from(i).unwrap())
2209 .unwrap_or_else(|| self.config.max_elements);
2210
2211 let ty = match kind {
2215 ElementKind::Passive | ElementKind::Declared => self.arbitrary_ref_type(u)?,
2216 ElementKind::Active { table, .. } => {
2217 let idx = table.unwrap_or(0);
2218 self.arbitrary_matching_ref_type(u, self.tables[idx as usize].element_type)?
2219 }
2220 };
2221
2222 let can_use_function_list = ty == RefType::FUNCREF;
2226 if !self.config.reference_types_enabled {
2227 assert!(can_use_function_list);
2228 }
2229
2230 let mut func_candidates = Vec::new();
2233 if can_use_function_list {
2234 match ty.heap_type {
2235 HeapType::Abstract {
2236 ty: AbstractHeapType::Func,
2237 ..
2238 } => {
2239 func_candidates.extend(0..self.funcs.len() as u32);
2240 }
2241 HeapType::Concrete(ty) => {
2242 for (i, (fty, _)) in self.funcs.iter().enumerate() {
2243 if *fty == ty {
2244 func_candidates.push(i as u32);
2245 }
2246 }
2247 }
2248 _ => {}
2249 }
2250 }
2251
2252 let items = if !self.config.reference_types_enabled
2257 || (can_use_function_list && u.arbitrary()?)
2258 {
2259 let mut init = vec![];
2260 if func_candidates.len() > 0 {
2261 arbitrary_loop(u, self.config.min_elements, max, |u| {
2262 let func_idx = *u.choose(&func_candidates)?;
2263 init.push(func_idx);
2264 Ok(true)
2265 })?;
2266 }
2267 Elements::Functions(init)
2268 } else {
2269 let mut init = vec![];
2270 arbitrary_loop(u, self.config.min_elements, max, |u| {
2271 init.push(self.arbitrary_const_expr(ValType::Ref(ty), u)?);
2272 Ok(true)
2273 })?;
2274 Elements::Expressions(init)
2275 };
2276
2277 self.elems.push(ElementSegment { kind, ty, items });
2278 Ok(true)
2279 },
2280 )
2281 }
2282
2283 fn arbitrary_code(&mut self, u: &mut Unstructured) -> Result<()> {
2284 self.compute_interesting_values();
2285
2286 self.code.reserve(self.num_defined_funcs);
2287 let mut allocs = CodeBuilderAllocations::new(self, self.config.exports.is_some());
2288 for (idx, ty) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() {
2289 let shared = self.is_shared_type(*idx);
2290 let body = self.arbitrary_func_body(u, ty, &mut allocs, shared)?;
2291 self.code.push(body);
2292 }
2293 allocs.finish(u, self)?;
2294 Ok(())
2295 }
2296
2297 fn arbitrary_func_body(
2298 &self,
2299 u: &mut Unstructured,
2300 ty: &FuncType,
2301 allocs: &mut CodeBuilderAllocations,
2302 shared: bool,
2303 ) -> Result<Code> {
2304 let mut locals = self.arbitrary_locals(u)?;
2305 let builder = allocs.builder(ty, &mut locals, shared);
2306 let instructions = if self.config.allow_invalid_funcs && u.arbitrary().unwrap_or(false) {
2307 Instructions::Arbitrary(arbitrary_vec_u8(u)?)
2308 } else {
2309 Instructions::Generated(builder.arbitrary(u, self)?)
2310 };
2311
2312 Ok(Code {
2313 locals,
2314 instructions,
2315 })
2316 }
2317
2318 fn arbitrary_locals(&self, u: &mut Unstructured) -> Result<Vec<ValType>> {
2319 let mut ret = Vec::new();
2320 arbitrary_loop(u, 0, 100, |u| {
2321 ret.push(self.arbitrary_valtype(u)?);
2322 Ok(true)
2323 })?;
2324 Ok(ret)
2325 }
2326
2327 fn arbitrary_data(&mut self, u: &mut Unstructured) -> Result<()> {
2328 let memories = self.memories.len() as u32;
2331 if memories == 0 && !self.config.bulk_memory_enabled {
2332 return Ok(());
2333 }
2334 let disallow_traps = self.config.disallow_traps;
2335 let mut choices32: Vec<Box<dyn Fn(&mut Unstructured, u64, usize) -> Result<Offset>>> =
2336 vec![];
2337 choices32.push(Box::new(|u, min_size, data_len| {
2338 let min = u32::try_from(min_size.saturating_mul(64 * 1024))
2339 .unwrap_or(u32::MAX)
2340 .into();
2341 let max = if disallow_traps { min } else { u32::MAX.into() };
2342 Ok(Offset::Const32(
2343 arbitrary_offset(u, min, max, data_len)? as i32
2344 ))
2345 }));
2346 let mut choices64: Vec<Box<dyn Fn(&mut Unstructured, u64, usize) -> Result<Offset>>> =
2347 vec![];
2348 choices64.push(Box::new(|u, min_size, data_len| {
2349 let min = min_size.saturating_mul(64 * 1024);
2350 let max = if disallow_traps { min } else { u64::MAX };
2351 Ok(Offset::Const64(
2352 arbitrary_offset(u, min, max, data_len)? as i64
2353 ))
2354 }));
2355 if !self.config.disallow_traps {
2356 for i in self.globals_for_const_expr(ValType::I32) {
2357 choices32.push(Box::new(move |_, _, _| Ok(Offset::Global(i))));
2358 }
2359 for i in self.globals_for_const_expr(ValType::I64) {
2360 choices64.push(Box::new(move |_, _, _| Ok(Offset::Global(i))));
2361 }
2362 }
2363
2364 let mut memories = Vec::new();
2370 for (i, mem) in self.memories.iter().enumerate() {
2371 if mem.minimum > 0 || u.int_in_range(0..=CHANCE_SEGMENT_ON_EMPTY)? == 0 {
2372 memories.push(i as u32);
2373 }
2374 }
2375
2376 if memories.is_empty() && !self.config.bulk_memory_enabled {
2380 return Ok(());
2381 }
2382
2383 arbitrary_loop(
2384 u,
2385 self.config.min_data_segments,
2386 self.config.max_data_segments,
2387 |u| {
2388 let mut init: Vec<u8> = u.arbitrary()?;
2389
2390 let kind =
2395 if self.config.bulk_memory_enabled && (memories.is_empty() || u.arbitrary()?) {
2396 DataSegmentKind::Passive
2397 } else {
2398 let memory_index = *u.choose(&memories)?;
2399 let mem = &self.memories[memory_index as usize];
2400 let f = if mem.memory64 {
2401 u.choose(&choices64)?
2402 } else {
2403 u.choose(&choices32)?
2404 };
2405 let mut offset = f(u, mem.minimum, init.len())?;
2406
2407 if self.config.disallow_traps {
2412 let max_size = (u64::MAX / 64 / 1024).min(mem.minimum) * 64 * 1024;
2413 init.truncate(max_size as usize);
2414 let max_offset = max_size - init.len() as u64;
2415 match &mut offset {
2416 Offset::Const32(x) => {
2417 *x = (*x as u64).min(max_offset) as i32;
2418 }
2419 Offset::Const64(x) => {
2420 *x = (*x as u64).min(max_offset) as i64;
2421 }
2422 Offset::Global(_) => unreachable!(),
2423 }
2424 }
2425 DataSegmentKind::Active {
2426 offset,
2427 memory_index,
2428 }
2429 };
2430 self.data.push(DataSegment { kind, init });
2431 Ok(true)
2432 },
2433 )
2434 }
2435
2436 fn params_results(&self, ty: &BlockType) -> (Vec<ValType>, Vec<ValType>) {
2437 match ty {
2438 BlockType::Empty => (vec![], vec![]),
2439 BlockType::Result(t) => (vec![], vec![*t]),
2440 BlockType::FunctionType(ty) => {
2441 let ty = self.func_type(*ty);
2442 (ty.params.to_vec(), ty.results.to_vec())
2443 }
2444 }
2445 }
2446
2447 fn globals_for_const_expr(&self, ty: ValType) -> impl Iterator<Item = u32> + '_ {
2450 let num_imported_globals = self.globals.len() - self.defined_globals.len();
2453 let max_global = if self.config.gc_enabled {
2454 self.globals.len()
2455 } else {
2456 num_imported_globals
2457 };
2458
2459 self.globals[..max_global]
2460 .iter()
2461 .enumerate()
2462 .filter_map(move |(i, g)| {
2463 if !g.mutable && self.val_type_is_sub_type(g.val_type, ty) {
2467 Some(i as u32)
2468 } else {
2469 None
2470 }
2471 })
2472 }
2473
2474 fn compute_interesting_values(&mut self) {
2475 debug_assert!(self.interesting_values32.is_empty());
2476 debug_assert!(self.interesting_values64.is_empty());
2477
2478 let mut interesting_values32 = HashSet::new();
2479 let mut interesting_values64 = HashSet::new();
2480
2481 let mut interesting = |val: u64| {
2482 interesting_values32.insert(val as u32);
2483 interesting_values64.insert(val);
2484 };
2485
2486 interesting(0);
2488
2489 interesting(u8::MAX as _);
2491 interesting(u16::MAX as _);
2492 interesting(u32::MAX as _);
2493 interesting(u64::MAX);
2494
2495 interesting(i8::MIN as _);
2497 interesting(i16::MIN as _);
2498 interesting(i32::MIN as _);
2499 interesting(i64::MIN as _);
2500
2501 for i in 0..64 {
2502 interesting(1 << i);
2504
2505 interesting(!(1 << i));
2507
2508 interesting((1 << i) - 1);
2510
2511 interesting(((1_i64 << 63) >> i) as _);
2513 }
2514
2515 for pattern in [0b01010101, 0b00010001, 0b00010001, 0b00000001] {
2517 for b in [pattern, !pattern] {
2518 interesting(u64::from_ne_bytes([b, b, b, b, b, b, b, b]));
2519 }
2520 }
2521
2522 let mut interesting_f64 = |x: f64| interesting(x.to_bits());
2524 interesting_f64(0.0);
2525 interesting_f64(-0.0);
2526 interesting_f64(f64::INFINITY);
2527 interesting_f64(f64::NEG_INFINITY);
2528 interesting_f64(f64::EPSILON);
2529 interesting_f64(-f64::EPSILON);
2530 interesting_f64(f64::MIN);
2531 interesting_f64(f64::MIN_POSITIVE);
2532 interesting_f64(f64::MAX);
2533 interesting_f64(f64::NAN);
2534 let mut interesting_f32 = |x: f32| interesting(x.to_bits() as _);
2535 interesting_f32(0.0);
2536 interesting_f32(-0.0);
2537 interesting_f32(f32::INFINITY);
2538 interesting_f32(f32::NEG_INFINITY);
2539 interesting_f32(f32::EPSILON);
2540 interesting_f32(-f32::EPSILON);
2541 interesting_f32(f32::MIN);
2542 interesting_f32(f32::MIN_POSITIVE);
2543 interesting_f32(f32::MAX);
2544 interesting_f32(f32::NAN);
2545
2546 for t in self.tables.iter() {
2548 interesting(t.minimum as _);
2549 if let Some(x) = t.minimum.checked_add(1) {
2550 interesting(x as _);
2551 }
2552
2553 if let Some(x) = t.maximum {
2554 interesting(x as _);
2555 if let Some(y) = x.checked_add(1) {
2556 interesting(y as _);
2557 }
2558 }
2559 }
2560
2561 for m in self.memories.iter() {
2563 let min = m.minimum.saturating_mul(crate::page_size(m).into());
2564 interesting(min);
2565 for i in 0..5 {
2566 if let Some(x) = min.checked_add(1 << i) {
2567 interesting(x);
2568 }
2569 if let Some(x) = min.checked_sub(1 << i) {
2570 interesting(x);
2571 }
2572 }
2573
2574 if let Some(max) = m.maximum {
2575 let max = max.saturating_mul(crate::page_size(m).into());
2576 interesting(max);
2577 for i in 0..5 {
2578 if let Some(x) = max.checked_add(1 << i) {
2579 interesting(x);
2580 }
2581 if let Some(x) = max.checked_sub(1 << i) {
2582 interesting(x);
2583 }
2584 }
2585 }
2586 }
2587
2588 self.interesting_values32.extend(interesting_values32);
2589 self.interesting_values64.extend(interesting_values64);
2590
2591 self.interesting_values32.sort();
2593 self.interesting_values64.sort();
2594 }
2595
2596 fn arbitrary_const_instruction(
2597 &self,
2598 ty: ValType,
2599 u: &mut Unstructured<'_>,
2600 ) -> Result<Instruction> {
2601 debug_assert!(self.interesting_values32.len() > 0);
2602 debug_assert!(self.interesting_values64.len() > 0);
2603 match ty {
2604 ValType::I32 => Ok(Instruction::I32Const(if u.arbitrary()? {
2605 *u.choose(&self.interesting_values32)? as i32
2606 } else {
2607 u.arbitrary()?
2608 })),
2609 ValType::I64 => Ok(Instruction::I64Const(if u.arbitrary()? {
2610 *u.choose(&self.interesting_values64)? as i64
2611 } else {
2612 u.arbitrary()?
2613 })),
2614 ValType::F32 => Ok(Instruction::F32Const(if u.arbitrary()? {
2615 f32::from_bits(*u.choose(&self.interesting_values32)?)
2616 } else {
2617 u.arbitrary()?
2618 })),
2619 ValType::F64 => Ok(Instruction::F64Const(if u.arbitrary()? {
2620 f64::from_bits(*u.choose(&self.interesting_values64)?)
2621 } else {
2622 u.arbitrary()?
2623 })),
2624 ValType::V128 => Ok(Instruction::V128Const(if u.arbitrary()? {
2625 let upper = (*u.choose(&self.interesting_values64)? as i128) << 64;
2626 let lower = *u.choose(&self.interesting_values64)? as i128;
2627 upper | lower
2628 } else {
2629 u.arbitrary()?
2630 })),
2631 ValType::Ref(ty) => {
2632 assert!(ty.nullable);
2633 Ok(Instruction::RefNull(ty.heap_type))
2634 }
2635 }
2636 }
2637
2638 fn propagate_shared<T>(&mut self, must_share: bool, mut f: impl FnMut(&mut Self) -> T) -> T {
2639 let tmp = mem::replace(&mut self.must_share, must_share);
2640 let result = f(self);
2641 self.must_share = tmp;
2642 result
2643 }
2644
2645 fn arbitrary_shared(&self, u: &mut Unstructured) -> Result<bool> {
2646 if self.must_share {
2647 Ok(true)
2648 } else {
2649 Ok(self.config.shared_everything_threads_enabled && u.ratio(1, 4)?)
2650 }
2651 }
2652
2653 fn is_shared_ref_type(&self, ty: RefType) -> bool {
2654 match ty.heap_type {
2655 HeapType::Abstract { shared, .. } => shared,
2656 HeapType::Concrete(i) => self.types[i as usize].composite_type.shared,
2657 }
2658 }
2659
2660 fn is_shared_type(&self, index: u32) -> bool {
2661 let index = usize::try_from(index).unwrap();
2662 let ty = self.types.get(index).unwrap();
2663 ty.composite_type.shared
2664 }
2665}
2666
2667pub(crate) fn arbitrary_limits64(
2668 u: &mut Unstructured,
2669 min_minimum: Option<u64>,
2670 max_minimum: u64,
2671 max_required: bool,
2672 max_inbounds: u64,
2673) -> Result<(u64, Option<u64>)> {
2674 assert!(
2675 min_minimum.unwrap_or(0) <= max_minimum,
2676 "{} <= {max_minimum}",
2677 min_minimum.unwrap_or(0),
2678 );
2679 assert!(
2680 min_minimum.unwrap_or(0) <= max_inbounds,
2681 "{} <= {max_inbounds}",
2682 min_minimum.unwrap_or(0),
2683 );
2684
2685 let min = gradually_grow(u, min_minimum.unwrap_or(0), max_inbounds, max_minimum)?;
2686 assert!(min <= max_minimum, "{min} <= {max_minimum}");
2687
2688 let max = if max_required || u.arbitrary().unwrap_or(false) {
2689 Some(u.int_in_range(min..=max_minimum)?)
2690 } else {
2691 None
2692 };
2693 assert!(min <= max.unwrap_or(min), "{min} <= {}", max.unwrap_or(min));
2694
2695 Ok((min, max))
2696}
2697
2698pub(crate) fn configured_valtypes(config: &Config) -> Vec<ValType> {
2699 let mut valtypes = Vec::with_capacity(25);
2700 valtypes.push(ValType::I32);
2701 valtypes.push(ValType::I64);
2702 if config.allow_floats {
2703 valtypes.push(ValType::F32);
2704 valtypes.push(ValType::F64);
2705 }
2706 if config.simd_enabled {
2707 valtypes.push(ValType::V128);
2708 }
2709 if config.gc_enabled && config.reference_types_enabled {
2710 for nullable in [
2711 true,
2718 ] {
2719 use AbstractHeapType::*;
2720 let abs_ref_types = [
2721 Any, Eq, I31, Array, Struct, None, Func, NoFunc, Extern, NoExtern,
2722 ];
2723 valtypes.extend(
2724 abs_ref_types
2725 .iter()
2726 .map(|&ty| ValType::Ref(RefType::new_abstract(ty, nullable, false))),
2727 );
2728 if config.shared_everything_threads_enabled {
2729 valtypes.extend(
2730 abs_ref_types
2731 .iter()
2732 .map(|&ty| ValType::Ref(RefType::new_abstract(ty, nullable, true))),
2733 );
2734 }
2735 }
2736 } else if config.reference_types_enabled {
2737 valtypes.push(ValType::EXTERNREF);
2738 valtypes.push(ValType::FUNCREF);
2739 }
2740 valtypes
2741}
2742
2743pub(crate) fn arbitrary_table_type(
2744 u: &mut Unstructured,
2745 config: &Config,
2746 module: Option<&Module>,
2747) -> Result<TableType> {
2748 let table64 = config.memory64_enabled && u.arbitrary()?;
2749 let max_inbounds = 10_000;
2752 let min_elements = if config.disallow_traps { Some(1) } else { None };
2753 let max_elements = min_elements.unwrap_or(0).max(config.max_table_elements);
2754 let (minimum, maximum) = arbitrary_limits64(
2755 u,
2756 min_elements,
2757 max_elements,
2758 config.table_max_size_required,
2759 max_inbounds.min(max_elements),
2760 )?;
2761 if config.disallow_traps {
2762 assert!(minimum > 0);
2763 }
2764 let element_type = match module {
2765 Some(module) => module.arbitrary_ref_type(u)?,
2766 None => RefType::FUNCREF,
2767 };
2768
2769 let shared = match module {
2771 Some(module) => module.is_shared_ref_type(element_type),
2772 None => false,
2773 };
2774
2775 Ok(TableType {
2776 element_type,
2777 minimum,
2778 maximum,
2779 table64,
2780 shared,
2781 })
2782}
2783
2784pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &Config) -> Result<MemoryType> {
2785 let shared = config.threads_enabled && u.ratio(1, 4)?;
2788
2789 let memory64 = config.memory64_enabled && u.arbitrary()?;
2790 let page_size_log2 = if config.custom_page_sizes_enabled && u.arbitrary()? {
2791 Some(if u.arbitrary()? { 0 } else { 16 })
2792 } else {
2793 None
2794 };
2795
2796 let min_pages = if config.disallow_traps { Some(1) } else { None };
2797 let max_pages = min_pages.unwrap_or(0).max(if memory64 {
2798 u64::try_from(config.max_memory64_bytes >> page_size_log2.unwrap_or(16))
2799 .unwrap_or(u64::MAX as u64)
2803 } else {
2804 u32::try_from(config.max_memory32_bytes >> page_size_log2.unwrap_or(16))
2805 .unwrap_or(u32::MAX)
2808 .into()
2809 });
2810
2811 let max_all_mems_in_bytes = 1 << 30;
2813 let max_this_mem_in_bytes = max_all_mems_in_bytes / u64::try_from(config.max_memories).unwrap();
2814 let max_inbounds = max_this_mem_in_bytes >> page_size_log2.unwrap_or(16);
2815 let max_inbounds = max_inbounds.clamp(min_pages.unwrap_or(0), max_pages);
2816
2817 let (minimum, maximum) = arbitrary_limits64(
2818 u,
2819 min_pages,
2820 max_pages,
2821 config.memory_max_size_required || shared,
2822 max_inbounds,
2823 )?;
2824
2825 Ok(MemoryType {
2826 minimum,
2827 maximum,
2828 memory64,
2829 shared,
2830 page_size_log2,
2831 })
2832}
2833
2834pub(crate) fn arbitrary_tag_type(
2835 u: &mut Unstructured,
2836 candidate_func_types: &[u32],
2837 get_func_type: impl FnOnce(u32) -> Rc<FuncType>,
2838) -> Result<TagType> {
2839 let max = candidate_func_types.len() - 1;
2840 let ty = candidate_func_types[u.int_in_range(0..=max)?];
2841 Ok(TagType {
2842 func_type_idx: ty,
2843 func_type: get_func_type(ty),
2844 })
2845}
2846
2847fn gradually_grow(u: &mut Unstructured, min: u64, max_inbounds: u64, max: u64) -> Result<u64> {
2855 if min == max {
2856 return Ok(min);
2857 }
2858 let x = {
2859 let min = min as f64;
2860 let max = max as f64;
2861 let max_inbounds = max_inbounds as f64;
2862 let x = u.arbitrary::<u32>()?;
2863 let x = f64::from(x);
2864 let x = map_custom(
2865 x,
2866 f64::from(u32::MIN)..f64::from(u32::MAX),
2867 min..max_inbounds,
2868 min..max,
2869 );
2870 assert!(min <= x, "{min} <= {x}");
2871 assert!(x <= max, "{x} <= {max}");
2872 x.round() as u64
2873 };
2874
2875 return Ok(x.clamp(min, max));
2878
2879 fn map_custom(
2886 value: f64,
2887 input: Range<f64>,
2888 output_inbounds: Range<f64>,
2889 output: Range<f64>,
2890 ) -> f64 {
2891 assert!(!value.is_nan(), "{}", value);
2892 assert!(value.is_finite(), "{}", value);
2893 assert!(input.start < input.end, "{} < {}", input.start, input.end);
2894 assert!(
2895 output.start < output.end,
2896 "{} < {}",
2897 output.start,
2898 output.end
2899 );
2900 assert!(value >= input.start, "{} >= {}", value, input.start);
2901 assert!(value <= input.end, "{} <= {}", value, input.end);
2902 assert!(
2903 output.start <= output_inbounds.start,
2904 "{} <= {}",
2905 output.start,
2906 output_inbounds.start
2907 );
2908 assert!(
2909 output_inbounds.end <= output.end,
2910 "{} <= {}",
2911 output_inbounds.end,
2912 output.end
2913 );
2914
2915 let x = map_linear(value, input, 0.0..1.0);
2916 let result = if x < PCT_INBOUNDS {
2917 if output_inbounds.start == output_inbounds.end {
2918 output_inbounds.start
2919 } else {
2920 let unscaled = x * x * x * x * x * x;
2921 map_linear(unscaled, 0.0..1.0, output_inbounds)
2922 }
2923 } else {
2924 map_linear(x, 0.0..1.0, output.clone())
2925 };
2926
2927 assert!(result >= output.start, "{} >= {}", result, output.start);
2928 assert!(result <= output.end, "{} <= {}", result, output.end);
2929 result
2930 }
2931
2932 fn map_linear(
2937 value: f64,
2938 Range {
2939 start: in_low,
2940 end: in_high,
2941 }: Range<f64>,
2942 Range {
2943 start: out_low,
2944 end: out_high,
2945 }: Range<f64>,
2946 ) -> f64 {
2947 assert!(!value.is_nan(), "{}", value);
2948 assert!(value.is_finite(), "{}", value);
2949 assert!(in_low < in_high, "{} < {}", in_low, in_high);
2950 assert!(out_low < out_high, "{} < {}", out_low, out_high);
2951 assert!(value >= in_low, "{} >= {}", value, in_low);
2952 assert!(value <= in_high, "{} <= {}", value, in_high);
2953
2954 let dividend = out_high - out_low;
2955 let divisor = in_high - in_low;
2956 let slope = dividend / divisor;
2957 let result = out_low + (slope * (value - in_low));
2958
2959 assert!(result >= out_low, "{} >= {}", result, out_low);
2960 assert!(result <= out_high, "{} <= {}", result, out_high);
2961 result
2962 }
2963}
2964
2965fn arbitrary_offset(
2969 u: &mut Unstructured,
2970 limit_min: u64,
2971 limit_max: u64,
2972 segment_size: usize,
2973) -> Result<u64> {
2974 let size = u64::try_from(segment_size).unwrap();
2975
2976 if size > limit_min {
2979 u.int_in_range(0..=limit_max)
2980 } else {
2981 gradually_grow(u, 0, limit_min - size, limit_max)
2982 }
2983}
2984
2985fn unique_import_strings(max_size: usize, u: &mut Unstructured) -> Result<(String, String)> {
2986 let module = limited_string(max_size, u)?;
2987 let field = limited_string(max_size, u)?;
2988 Ok((module, field))
2989}
2990
2991fn arbitrary_vec_u8(u: &mut Unstructured) -> Result<Vec<u8>> {
2992 let size = u.arbitrary_len::<u8>()?;
2993 Ok(u.bytes(size)?.to_vec())
2994}
2995
2996impl EntityType {
2997 fn size(&self) -> u32 {
2998 match self {
2999 EntityType::Tag(_)
3000 | EntityType::Global(_)
3001 | EntityType::Table(_)
3002 | EntityType::Memory(_) => 1,
3003 EntityType::Func(_, ty) => 1 + (ty.params.len() + ty.results.len()) as u32,
3004 }
3005 }
3006}
3007
3008#[derive(Clone, Copy, Debug, Default)]
3019#[cfg_attr(
3020 feature = "serde",
3021 derive(serde_derive::Deserialize, serde_derive::Serialize)
3022)]
3023pub struct InstructionKinds(pub(crate) FlagSet<InstructionKind>);
3024
3025impl InstructionKinds {
3026 pub fn new(kinds: &[InstructionKind]) -> Self {
3028 Self(kinds.iter().fold(FlagSet::default(), |ks, k| ks | *k))
3029 }
3030
3031 pub fn all() -> Self {
3033 Self(FlagSet::full())
3034 }
3035
3036 pub fn none() -> Self {
3038 Self(FlagSet::default())
3039 }
3040
3041 #[inline]
3043 pub fn contains(&self, kind: InstructionKind) -> bool {
3044 self.0.contains(kind)
3045 }
3046
3047 pub fn without_floats(&self) -> Self {
3049 let mut floatless = self.0;
3050 if floatless.contains(InstructionKind::Numeric) {
3051 floatless -= InstructionKind::Numeric;
3052 floatless |= InstructionKind::NumericInt;
3053 }
3054 if floatless.contains(InstructionKind::Vector) {
3055 floatless -= InstructionKind::Vector;
3056 floatless |= InstructionKind::VectorInt;
3057 }
3058 if floatless.contains(InstructionKind::Memory) {
3059 floatless -= InstructionKind::Memory;
3060 floatless |= InstructionKind::MemoryInt;
3061 }
3062 Self(floatless)
3063 }
3064}
3065
3066flags! {
3067 #[allow(missing_docs)]
3070 #[cfg_attr(feature = "_internal_cli", derive(serde_derive::Deserialize))]
3071 pub enum InstructionKind: u16 {
3072 NumericInt = 1 << 0,
3073 Numeric = (1 << 1) | (1 << 0),
3074 VectorInt = 1 << 2,
3075 Vector = (1 << 3) | (1 << 2),
3076 Reference = 1 << 4,
3077 Parametric = 1 << 5,
3078 Variable = 1 << 6,
3079 Table = 1 << 7,
3080 MemoryInt = 1 << 8,
3081 Memory = (1 << 9) | (1 << 8),
3082 Control = 1 << 10,
3083 Aggregate = 1 << 11,
3084 }
3085}
3086
3087impl FromStr for InstructionKinds {
3088 type Err = String;
3089 fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
3090 let mut kinds = vec![];
3091 for part in s.split(",") {
3092 let kind = InstructionKind::from_str(part)?;
3093 kinds.push(kind);
3094 }
3095 Ok(InstructionKinds::new(&kinds))
3096 }
3097}
3098
3099impl FromStr for InstructionKind {
3100 type Err = String;
3101 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3102 match s.to_lowercase().as_str() {
3103 "numeric_non_float" => Ok(InstructionKind::NumericInt),
3104 "numeric" => Ok(InstructionKind::Numeric),
3105 "vector_non_float" => Ok(InstructionKind::VectorInt),
3106 "vector" => Ok(InstructionKind::Vector),
3107 "reference" => Ok(InstructionKind::Reference),
3108 "parametric" => Ok(InstructionKind::Parametric),
3109 "variable" => Ok(InstructionKind::Variable),
3110 "table" => Ok(InstructionKind::Table),
3111 "memory_non_float" => Ok(InstructionKind::MemoryInt),
3112 "memory" => Ok(InstructionKind::Memory),
3113 "control" => Ok(InstructionKind::Control),
3114 _ => Err(format!("unknown instruction kind: {}", s)),
3115 }
3116 }
3117}