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, 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 let mut generate_arbitrary_imports = true;
445 let mut generate_arbitrary_exports = true;
446 if self.imports_exports_from_module_shape(u)? {
447 generate_arbitrary_imports = false;
448 generate_arbitrary_exports = false;
449 }
450 if self.arbitrary_imports_from_available(u)? {
456 generate_arbitrary_imports = false;
457 }
458 self.arbitrary_types(u)?;
459 if generate_arbitrary_imports {
460 self.arbitrary_imports(u)?;
461 }
462
463 self.should_encode_imports = !self.imports.is_empty() || u.arbitrary()?;
464
465 self.arbitrary_tags(u)?;
466 self.arbitrary_funcs(u)?;
467 self.arbitrary_tables(u)?;
468 self.arbitrary_memories(u)?;
469 self.arbitrary_globals(u)?;
470 if self.required_exports(u)? {
471 generate_arbitrary_exports = false;
472 }
473 if generate_arbitrary_exports {
474 self.arbitrary_exports(u)?;
475 }
476 self.should_encode_types = !self.types.is_empty() || u.arbitrary()?;
477 self.arbitrary_start(u)?;
478 self.arbitrary_elems(u)?;
479 self.arbitrary_data(u)?;
480 self.arbitrary_code(u)?;
481 Ok(())
482 }
483
484 #[inline]
485 fn val_type_is_sub_type(&self, a: ValType, b: ValType) -> bool {
486 match (a, b) {
487 (a, b) if a == b => true,
488 (ValType::Ref(a), ValType::Ref(b)) => self.ref_type_is_sub_type(a, b),
489 _ => false,
490 }
491 }
492
493 fn ref_type_is_sub_type(&self, a: RefType, b: RefType) -> bool {
495 if a == b {
496 return true;
497 }
498
499 if a.nullable && !b.nullable {
500 return false;
501 }
502
503 self.heap_type_is_sub_type(a.heap_type, b.heap_type)
504 }
505
506 fn heap_type_is_sub_type(&self, a: HeapType, b: HeapType) -> bool {
507 use AbstractHeapType::*;
508 use CompositeInnerType as CT;
509 use HeapType as HT;
510 match (a, b) {
511 (a, b) if a == b => true,
512
513 (
514 HT::Abstract {
515 shared: a_shared,
516 ty: a_ty,
517 },
518 HT::Abstract {
519 shared: b_shared,
520 ty: b_ty,
521 },
522 ) => {
523 a_shared == b_shared
524 && match (a_ty, b_ty) {
525 (Eq | I31 | Struct | Array | None, Any) => true,
526 (I31 | Struct | Array | None, Eq) => true,
527 (NoExtern, Extern) => true,
528 (NoFunc, Func) => true,
529 (None, I31 | Array | Struct) => true,
530 (NoExn, Exn) => true,
531 _ => false,
532 }
533 }
534
535 (HT::Concrete(a), HT::Abstract { shared, ty }) => {
536 let a_ty = &self.ty(a).composite_type;
537 if a_ty.shared != shared {
538 return false;
539 }
540 match ty {
541 Eq | Any => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
542 Struct => matches!(a_ty.inner, CT::Struct(_)),
543 Array => matches!(a_ty.inner, CT::Array(_)),
544 Func => matches!(a_ty.inner, CT::Func(_)),
545 _ => false,
546 }
547 }
548
549 (HT::Abstract { shared, ty }, HT::Concrete(b)) => {
550 let b_ty = &self.ty(b).composite_type;
551 if shared != b_ty.shared {
552 return false;
553 }
554 match ty {
555 None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
556 NoFunc => matches!(b_ty.inner, CT::Func(_)),
557 _ => false,
558 }
559 }
560
561 (HT::Concrete(mut a), HT::Concrete(b)) => loop {
562 if a == b {
563 return true;
564 }
565 if let Some(supertype) = self.ty(a).supertype {
566 a = supertype;
567 } else {
568 return false;
569 }
570 },
571 }
572 }
573
574 fn arbitrary_types(&mut self, u: &mut Unstructured) -> Result<()> {
575 assert!(self.config.min_types <= self.config.max_types);
576 while self.types.len() < self.config.min_types {
577 self.arbitrary_rec_group(u, AllowEmptyRecGroup::No)?;
578 }
579 while self.types.len() < self.config.max_types {
580 let keep_going = u.arbitrary().unwrap_or(false);
581 if !keep_going {
582 break;
583 }
584 self.arbitrary_rec_group(u, AllowEmptyRecGroup::Yes)?;
585 }
586 Ok(())
587 }
588
589 fn add_type(&mut self, ty: SubType) -> u32 {
590 let index = u32::try_from(self.types.len()).unwrap();
591
592 if let Some(supertype) = ty.supertype {
593 assert_eq!(self.is_shared_type(supertype), ty.composite_type.shared);
594 self.super_to_sub_types
595 .entry(supertype)
596 .or_default()
597 .push(index);
598 }
599
600 let list = match &ty.composite_type.inner {
601 CompositeInnerType::Array(_) => &mut self.array_types,
602 CompositeInnerType::Func(_) => &mut self.func_types,
603 CompositeInnerType::Struct(_) => &mut self.struct_types,
604 };
605 list.push(index);
606
607 const MAX_SUBTYPING_DEPTH: u32 = 60;
615 if !ty.is_final && ty.depth < MAX_SUBTYPING_DEPTH {
616 self.can_subtype.push(index);
617 }
618
619 self.types.push(ty);
620 index
621 }
622
623 fn arbitrary_rec_group(
624 &mut self,
625 u: &mut Unstructured,
626 kind: AllowEmptyRecGroup,
627 ) -> Result<()> {
628 let rec_group_start = self.types.len();
629
630 assert!(matches!(self.max_type_limit, MaxTypeLimit::ModuleTypes));
631
632 if self.config.gc_enabled {
633 if self.rec_groups.len() > 0 && u.ratio(1, u8::MAX)? {
635 return self.clone_rec_group(u, kind);
636 }
637
638 let max_rec_group_size = self.config.max_types - self.types.len();
640 let min_rec_group_size = match kind {
641 AllowEmptyRecGroup::Yes => 0,
642 AllowEmptyRecGroup::No => 1,
643 };
644 let rec_group_size = u.int_in_range(min_rec_group_size..=max_rec_group_size)?;
645 let type_ref_limit = u32::try_from(self.types.len() + rec_group_size).unwrap();
646 self.max_type_limit = MaxTypeLimit::Num(type_ref_limit);
647 for _ in 0..rec_group_size {
648 let ty = self.arbitrary_sub_type(u)?;
649 self.add_type(ty);
650 }
651 } else {
652 let type_ref_limit = u32::try_from(self.types.len()).unwrap();
653 self.max_type_limit = MaxTypeLimit::Num(type_ref_limit);
654 let ty = self.arbitrary_sub_type(u)?;
655 self.add_type(ty);
656 }
657
658 self.max_type_limit = MaxTypeLimit::ModuleTypes;
659
660 self.rec_groups.push(rec_group_start..self.types.len());
661 Ok(())
662 }
663
664 fn clone_rec_group(&mut self, u: &mut Unstructured, kind: AllowEmptyRecGroup) -> Result<()> {
665 let group = u.choose(&self.rec_groups)?.clone();
670 if group.is_empty() && kind == AllowEmptyRecGroup::No {
671 return Ok(());
672 }
673 if group.len() > self.config.max_types.saturating_sub(self.types.len()) {
674 return Ok(());
675 }
676
677 let new_rec_group_start = self.types.len();
685 for index in group {
686 let orig_ty_index = u32::try_from(index).unwrap();
687 let ty = self.ty(orig_ty_index).clone();
688 self.add_type(ty);
689 }
690 self.rec_groups.push(new_rec_group_start..self.types.len());
691 Ok(())
692 }
693
694 fn arbitrary_sub_type(&mut self, u: &mut Unstructured) -> Result<SubType> {
695 if !self.config.gc_enabled {
696 let shared = self.arbitrary_shared(u)?;
697 let func_type = self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?;
698 let composite_type = CompositeType {
699 inner: CompositeInnerType::Func(func_type),
700 shared,
701 };
702 return Ok(SubType {
703 is_final: true,
704 supertype: None,
705 composite_type,
706 depth: 1,
707 });
708 }
709
710 if !self.can_subtype.is_empty() && u.ratio(1, 32_u8)? {
711 self.arbitrary_sub_type_of_super_type(u)
712 } else {
713 Ok(SubType {
714 is_final: u.arbitrary()?,
715 supertype: None,
716 composite_type: self.arbitrary_composite_type(u)?,
717 depth: 1,
718 })
719 }
720 }
721
722 fn arbitrary_sub_type_of_super_type(&mut self, u: &mut Unstructured) -> Result<SubType> {
723 let supertype = *u.choose(&self.can_subtype)?;
724 let mut composite_type = self.types[usize::try_from(supertype).unwrap()]
725 .composite_type
726 .clone();
727 match &mut composite_type.inner {
728 CompositeInnerType::Array(a) => {
729 a.0 = self.arbitrary_matching_field_type(u, a.0)?;
730 }
731 CompositeInnerType::Func(f) => {
732 *f = self.arbitrary_matching_func_type(u, f)?;
733 }
734 CompositeInnerType::Struct(s) => {
735 *s = self.propagate_shared(composite_type.shared, |m| {
736 m.arbitrary_matching_struct_type(u, s)
737 })?;
738 }
739 }
740 Ok(SubType {
741 is_final: u.arbitrary()?,
742 supertype: Some(supertype),
743 composite_type,
744 depth: 1 + self.types[supertype as usize].depth,
745 })
746 }
747
748 fn arbitrary_matching_struct_type(
749 &mut self,
750 u: &mut Unstructured,
751 ty: &StructType,
752 ) -> Result<StructType> {
753 let len_extra_fields = u.int_in_range(0..=5)?;
754 let mut fields = Vec::with_capacity(ty.fields.len() + len_extra_fields);
755 for field in ty.fields.iter() {
756 fields.push(self.arbitrary_matching_field_type(u, *field)?);
757 }
758 for _ in 0..len_extra_fields {
759 fields.push(self.arbitrary_field_type(u)?);
760 }
761 Ok(StructType {
762 fields: fields.into_boxed_slice(),
763 })
764 }
765
766 fn arbitrary_matching_field_type(
767 &mut self,
768 u: &mut Unstructured,
769 ty: FieldType,
770 ) -> Result<FieldType> {
771 if ty.mutable {
772 Ok(ty)
773 } else {
774 Ok(FieldType {
775 element_type: self.arbitrary_matching_storage_type(u, ty.element_type)?,
776 mutable: false,
777 })
778 }
779 }
780
781 fn arbitrary_matching_storage_type(
782 &mut self,
783 u: &mut Unstructured,
784 ty: StorageType,
785 ) -> Result<StorageType> {
786 match ty {
787 StorageType::I8 => Ok(StorageType::I8),
788 StorageType::I16 => Ok(StorageType::I16),
789 StorageType::Val(ty) => Ok(StorageType::Val(self.arbitrary_matching_val_type(u, ty)?)),
790 }
791 }
792
793 fn arbitrary_matching_val_type(
794 &mut self,
795 u: &mut Unstructured,
796 ty: ValType,
797 ) -> Result<ValType> {
798 match ty {
799 ValType::I32 => Ok(ValType::I32),
800 ValType::I64 => Ok(ValType::I64),
801 ValType::F32 => Ok(ValType::F32),
802 ValType::F64 => Ok(ValType::F64),
803 ValType::V128 => Ok(ValType::V128),
804 ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_matching_ref_type(u, ty)?)),
805 }
806 }
807
808 fn arbitrary_matching_ref_type(&self, u: &mut Unstructured, ty: RefType) -> Result<RefType> {
809 Ok(RefType {
810 nullable: ty.nullable,
811 heap_type: self.arbitrary_matching_heap_type(u, ty.heap_type)?,
812 })
813 }
814
815 fn arbitrary_matching_heap_type(&self, u: &mut Unstructured, ty: HeapType) -> Result<HeapType> {
816 use {AbstractHeapType as AHT, CompositeInnerType as CT, HeapType as HT};
817
818 if !self.config.gc_enabled {
819 return Ok(ty);
820 }
821
822 let mut choices = vec![ty];
823 match ty {
824 HT::Abstract { shared, ty } => {
825 use AbstractHeapType::*;
826 let add_abstract = |choices: &mut Vec<HT>, tys: &[AHT]| {
827 choices.extend(tys.iter().map(|&ty| HT::Abstract { shared, ty }));
828 };
829 let add_concrete = |choices: &mut Vec<HT>, tys: &[u32]| {
830 choices.extend(
831 tys.iter()
832 .filter(|&&idx| shared == self.is_shared_type(idx))
833 .copied()
834 .map(HT::Concrete),
835 );
836 };
837 match ty {
838 Any => {
839 add_abstract(&mut choices, &[Eq, Struct, Array, I31, None]);
840 add_concrete(&mut choices, &self.array_types);
841 add_concrete(&mut choices, &self.struct_types);
842 }
843 Eq => {
844 add_abstract(&mut choices, &[Struct, Array, I31, None]);
845 add_concrete(&mut choices, &self.array_types);
846 add_concrete(&mut choices, &self.struct_types);
847 }
848 Struct => {
849 add_abstract(&mut choices, &[Struct, None]);
850 add_concrete(&mut choices, &self.struct_types);
851 }
852 Array => {
853 add_abstract(&mut choices, &[Array, None]);
854 add_concrete(&mut choices, &self.array_types);
855 }
856 I31 => {
857 add_abstract(&mut choices, &[None]);
858 }
859 Func => {
860 add_abstract(&mut choices, &[NoFunc]);
861 add_concrete(&mut choices, &self.func_types);
862 }
863 Extern => {
864 add_abstract(&mut choices, &[NoExtern]);
865 }
866 Exn | NoExn | None | NoExtern | NoFunc | Cont | NoCont => {}
867 }
868 }
869 HT::Concrete(idx) => {
870 if let Some(subs) = self.super_to_sub_types.get(&idx) {
871 choices.extend(subs.iter().copied().map(HT::Concrete));
872 }
873 match self
874 .types
875 .get(usize::try_from(idx).unwrap())
876 .map(|ty| (ty.composite_type.shared, &ty.composite_type.inner))
877 {
878 Some((shared, CT::Array(_) | CT::Struct(_))) => choices.push(HT::Abstract {
879 shared,
880 ty: AbstractHeapType::None,
881 }),
882 Some((shared, CT::Func(_))) => choices.push(HT::Abstract {
883 shared,
884 ty: AbstractHeapType::NoFunc,
885 }),
886 None => {
887 }
893 }
894 }
895 }
896 Ok(*u.choose(&choices)?)
897 }
898
899 fn arbitrary_matching_func_type(
900 &mut self,
901 u: &mut Unstructured,
902 ty: &FuncType,
903 ) -> Result<Rc<FuncType>> {
904 let mut params = Vec::with_capacity(ty.params.len());
908 for param in &ty.params {
909 params.push(self.arbitrary_super_type_of_val_type(u, *param)?);
910 }
911 let mut results = Vec::with_capacity(ty.results.len());
912 for result in &ty.results {
913 results.push(self.arbitrary_matching_val_type(u, *result)?);
914 }
915 Ok(Rc::new(FuncType { params, results }))
916 }
917
918 fn arbitrary_super_type_of_val_type(
919 &mut self,
920 u: &mut Unstructured,
921 ty: ValType,
922 ) -> Result<ValType> {
923 match ty {
924 ValType::I32 => Ok(ValType::I32),
925 ValType::I64 => Ok(ValType::I64),
926 ValType::F32 => Ok(ValType::F32),
927 ValType::F64 => Ok(ValType::F64),
928 ValType::V128 => Ok(ValType::V128),
929 ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_super_type_of_ref_type(u, ty)?)),
930 }
931 }
932
933 fn arbitrary_super_type_of_ref_type(
934 &self,
935 u: &mut Unstructured,
936 ty: RefType,
937 ) -> Result<RefType> {
938 Ok(RefType {
939 nullable: true,
946 heap_type: self.arbitrary_super_type_of_heap_type(u, ty.heap_type)?,
947 })
948 }
949
950 fn arbitrary_super_type_of_heap_type(
951 &self,
952 u: &mut Unstructured,
953 ty: HeapType,
954 ) -> Result<HeapType> {
955 use {AbstractHeapType as AHT, CompositeInnerType as CT, HeapType as HT};
956
957 if !self.config.gc_enabled {
958 return Ok(ty);
959 }
960
961 let mut choices = vec![ty];
962 match ty {
963 HT::Abstract { shared, ty } => {
964 use AbstractHeapType::*;
965 let add_abstract = |choices: &mut Vec<HT>, tys: &[AHT]| {
966 choices.extend(tys.iter().map(|&ty| HT::Abstract { shared, ty }));
967 };
968 let add_concrete = |choices: &mut Vec<HT>, tys: &[u32]| {
969 choices.extend(
970 tys.iter()
971 .filter(|&&idx| shared == self.is_shared_type(idx))
972 .copied()
973 .map(HT::Concrete),
974 );
975 };
976 match ty {
977 None => {
978 add_abstract(&mut choices, &[Any, Eq, Struct, Array, I31]);
979 add_concrete(&mut choices, &self.array_types);
980 add_concrete(&mut choices, &self.struct_types);
981 }
982 NoExtern => {
983 add_abstract(&mut choices, &[Extern]);
984 }
985 NoFunc => {
986 add_abstract(&mut choices, &[Func]);
987 add_concrete(&mut choices, &self.func_types);
988 }
989 NoExn => {
990 add_abstract(&mut choices, &[Exn]);
991 }
992 Struct | Array | I31 => {
993 add_abstract(&mut choices, &[Any, Eq]);
994 }
995 Eq => {
996 add_abstract(&mut choices, &[Any]);
997 }
998 NoCont => {
999 add_abstract(&mut choices, &[Cont]);
1000 }
1001 Exn | Any | Func | Extern | Cont => {}
1002 }
1003 }
1004 HT::Concrete(mut idx) => {
1005 if let Some(sub_ty) = &self.types.get(usize::try_from(idx).unwrap()) {
1006 use AbstractHeapType::*;
1007 let ht = |ty| HT::Abstract {
1008 shared: sub_ty.composite_type.shared,
1009 ty,
1010 };
1011 match &sub_ty.composite_type.inner {
1012 CT::Array(_) => {
1013 choices.extend([ht(Any), ht(Eq), ht(Array)]);
1014 }
1015 CT::Func(_) => {
1016 choices.push(ht(Func));
1017 }
1018 CT::Struct(_) => {
1019 choices.extend([ht(Any), ht(Eq), ht(Struct)]);
1020 }
1021 }
1022 } else {
1023 }
1030 while let Some(supertype) = self
1031 .types
1032 .get(usize::try_from(idx).unwrap())
1033 .and_then(|ty| ty.supertype)
1034 {
1035 choices.push(HT::Concrete(supertype));
1036 idx = supertype;
1037 }
1038 }
1039 }
1040 Ok(*u.choose(&choices)?)
1041 }
1042
1043 fn arbitrary_composite_type(&mut self, u: &mut Unstructured) -> Result<CompositeType> {
1044 use CompositeInnerType as CT;
1045 let shared = self.arbitrary_shared(u)?;
1046
1047 if !self.config.gc_enabled {
1048 return Ok(CompositeType {
1049 shared,
1050 inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?),
1051 });
1052 }
1053
1054 match u.int_in_range(0..=2)? {
1055 0 => Ok(CompositeType {
1056 shared,
1057 inner: CT::Array(ArrayType(
1058 self.propagate_shared(shared, |m| m.arbitrary_field_type(u))?,
1059 )),
1060 }),
1061 1 => Ok(CompositeType {
1062 shared,
1063 inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?),
1064 }),
1065 2 => Ok(CompositeType {
1066 shared,
1067 inner: CT::Struct(self.propagate_shared(shared, |m| m.arbitrary_struct_type(u))?),
1068 }),
1069 _ => unreachable!(),
1070 }
1071 }
1072
1073 fn arbitrary_struct_type(&mut self, u: &mut Unstructured) -> Result<StructType> {
1074 let len = u.int_in_range(0..=20)?;
1075 let mut fields = Vec::with_capacity(len);
1076 for _ in 0..len {
1077 fields.push(self.arbitrary_field_type(u)?);
1078 }
1079 Ok(StructType {
1080 fields: fields.into_boxed_slice(),
1081 })
1082 }
1083
1084 fn arbitrary_field_type(&mut self, u: &mut Unstructured) -> Result<FieldType> {
1085 Ok(FieldType {
1086 element_type: self.arbitrary_storage_type(u)?,
1087 mutable: u.arbitrary()?,
1088 })
1089 }
1090
1091 fn arbitrary_storage_type(&mut self, u: &mut Unstructured) -> Result<StorageType> {
1092 match u.int_in_range(0..=2)? {
1093 0 => Ok(StorageType::I8),
1094 1 => Ok(StorageType::I16),
1095 2 => Ok(StorageType::Val(self.arbitrary_valtype(u)?)),
1096 _ => unreachable!(),
1097 }
1098 }
1099
1100 fn arbitrary_ref_type(&self, u: &mut Unstructured) -> Result<RefType> {
1101 if !self.config.reference_types_enabled {
1102 return Ok(RefType::FUNCREF);
1103 }
1104 Ok(RefType {
1105 nullable: true,
1106 heap_type: self.arbitrary_heap_type(u)?,
1107 })
1108 }
1109
1110 fn arbitrary_heap_type(&self, u: &mut Unstructured) -> Result<HeapType> {
1111 assert!(self.config.reference_types_enabled);
1112
1113 let concrete_type_limit = match self.max_type_limit {
1114 MaxTypeLimit::Num(n) => n,
1115 MaxTypeLimit::ModuleTypes => u32::try_from(self.types.len()).unwrap(),
1116 };
1117
1118 if self.config.gc_enabled && concrete_type_limit > 0 && u.arbitrary()? {
1119 let idx = u.int_in_range(0..=concrete_type_limit - 1)?;
1120 if let Some(ty) = self.types.get(idx as usize) {
1126 if !(self.must_share && !ty.composite_type.shared) {
1129 return Ok(HeapType::Concrete(idx));
1130 }
1131 }
1132 }
1133
1134 use AbstractHeapType::*;
1135 let mut choices = vec![Func, Extern];
1136 if self.config.exceptions_enabled {
1137 choices.push(Exn);
1138 }
1139 if self.config.gc_enabled {
1140 choices.extend(
1141 [Any, None, NoExtern, NoFunc, Eq, Struct, Array, I31]
1142 .iter()
1143 .copied(),
1144 );
1145 }
1146
1147 Ok(HeapType::Abstract {
1148 shared: self.arbitrary_shared(u)?,
1149 ty: *u.choose(&choices)?,
1150 })
1151 }
1152
1153 fn arbitrary_func_type(&mut self, u: &mut Unstructured) -> Result<Rc<FuncType>> {
1154 let mut params = vec![];
1155 let mut results = vec![];
1156 let max_params = 20;
1157 arbitrary_loop(u, 0, max_params, |u| {
1158 params.push(self.arbitrary_valtype(u)?);
1159 Ok(true)
1160 })?;
1161 let max_results = if self.config.multi_value_enabled {
1162 max_params
1163 } else {
1164 1
1165 };
1166 arbitrary_loop(u, 0, max_results, |u| {
1167 results.push(self.arbitrary_valtype(u)?);
1168 Ok(true)
1169 })?;
1170 Ok(Rc::new(FuncType { params, results }))
1171 }
1172
1173 fn can_add_local_or_import_tag(&self) -> bool {
1174 self.config.exceptions_enabled
1175 && self.has_tag_func_types()
1176 && self.tags.len() < self.config.max_tags
1177 }
1178
1179 fn can_add_local_or_import_func(&self) -> bool {
1180 !self.func_types.is_empty() && self.funcs.len() < self.config.max_funcs
1181 }
1182
1183 fn can_add_local_or_import_table(&self) -> bool {
1184 self.tables.len() < self.config.max_tables
1185 }
1186
1187 fn can_add_local_or_import_global(&self) -> bool {
1188 self.globals.len() < self.config.max_globals
1189 }
1190
1191 fn can_add_local_or_import_memory(&self) -> bool {
1192 self.memories.len() < self.config.max_memories
1193 }
1194
1195 fn imports_exports_from_module_shape(&mut self, u: &mut Unstructured) -> Result<bool> {
1196 let example_module = if let Some(wasm) = self.config.module_shape.clone() {
1197 wasm
1198 } else {
1199 return Ok(false);
1200 };
1201
1202 #[cfg(feature = "wasmparser")]
1203 {
1204 self._imports_exports_from_module_shape(u, &example_module)?;
1205 Ok(true)
1206 }
1207 #[cfg(not(feature = "wasmparser"))]
1208 {
1209 let _ = (example_module, u);
1210 panic!("support for `module_shape` was disabled at compile time");
1211 }
1212 }
1213
1214 #[cfg(feature = "wasmparser")]
1215 fn _imports_exports_from_module_shape(
1216 &mut self,
1217 u: &mut Unstructured,
1218 example_module: &[u8],
1219 ) -> Result<()> {
1220 let mut available_funcs: Vec<u32> = Vec::new();
1224 let mut available_tags: Vec<wasmparser::TagType> = Vec::new();
1225 let mut available_tables: Vec<wasmparser::TableType> = Vec::new();
1226 let mut available_globals: Vec<wasmparser::GlobalType> = Vec::new();
1227 let mut available_memories: Vec<wasmparser::MemoryType> = Vec::new();
1228
1229 let mut required_types: Vec<SubType> = Vec::new();
1230 let mut required_recgrps: Vec<usize> = Vec::new();
1231 let mut required_imports: Vec<wasmparser::Import> = Vec::new();
1232 let mut required_exports: Vec<wasmparser::Export> = Vec::new();
1233 let mut validator = wasmparser::Validator::new();
1234 validator
1235 .validate_all(example_module)
1236 .expect("Failed to validate `module_shape` module");
1237 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
1238 match payload.expect("could not parse the `module_shape` module") {
1239 wasmparser::Payload::TypeSection(type_reader) => {
1240 for recgrp in type_reader {
1241 let recgrp = recgrp.expect("could not read recursive group");
1242 required_recgrps.push(recgrp.types().len());
1243 for subtype in recgrp.into_types() {
1244 let mut subtype: SubType = subtype.try_into().unwrap();
1245 if let Some(supertype_idx) = subtype.supertype {
1246 subtype.depth = required_types[supertype_idx as usize].depth + 1;
1247 }
1248 required_types.push(subtype);
1249 }
1250 }
1251 }
1252 wasmparser::Payload::ImportSection(import_reader) => {
1253 for im in import_reader {
1254 let im = im.expect("could not read import");
1255 required_imports.push(im);
1256 }
1257 }
1258 wasmparser::Payload::ExportSection(export_reader) => {
1259 for ex in export_reader {
1260 let ex = ex.expect("could not read export");
1261 required_exports.push(ex);
1262 }
1263 }
1264 wasmparser::Payload::FunctionSection(function_reader) => {
1265 for func in function_reader {
1266 let func = func.expect("could not read function");
1267 available_funcs.push(func);
1268 }
1269 }
1270 wasmparser::Payload::TagSection(tag_reader) => {
1271 for tag in tag_reader {
1272 let tag = tag.expect("could not read tag");
1273 available_tags.push(tag);
1274 }
1275 }
1276 wasmparser::Payload::TableSection(table_reader) => {
1277 for table in table_reader {
1278 let table = table.expect("could not read table");
1279 available_tables.push(table.ty);
1280 }
1281 }
1282 wasmparser::Payload::MemorySection(memory_reader) => {
1283 for memory in memory_reader {
1284 let memory = memory.expect("could not read memory");
1285 available_memories.push(memory);
1286 }
1287 }
1288 wasmparser::Payload::GlobalSection(global_reader) => {
1289 for global in global_reader {
1290 let global = global.expect("could not read global");
1291 available_globals.push(global.ty);
1292 }
1293 }
1294 _ => {}
1295 }
1296 }
1297
1298 let mut recgrp_start_idx = self.types.len();
1301 for size in required_recgrps {
1302 self.rec_groups
1303 .push(recgrp_start_idx..recgrp_start_idx + size);
1304 recgrp_start_idx += size;
1305 }
1306 for ty in &required_types {
1307 self.add_type(ty.clone());
1308 }
1309
1310 let mut imported_funcs: Vec<u32> = Vec::new();
1314 let mut imported_tags: Vec<wasmparser::TagType> = Vec::new();
1315 let mut imported_tables: Vec<wasmparser::TableType> = Vec::new();
1316 let mut imported_globals: Vec<wasmparser::GlobalType> = Vec::new();
1317 let mut imported_memories: Vec<wasmparser::MemoryType> = Vec::new();
1318 let mut new_imports = Vec::with_capacity(required_imports.len());
1319 for import in required_imports {
1320 let entity_type = match &import.ty {
1321 wasmparser::TypeRef::Func(sig_idx) => {
1322 imported_funcs.push(*sig_idx);
1323 match required_types.get(*sig_idx as usize) {
1324 None => panic!("signature index refers to a type out of bounds"),
1325 Some(ty) => match &ty.composite_type.inner {
1326 CompositeInnerType::Func(func_type) => {
1327 let entity = EntityType::Func(*sig_idx, Rc::clone(func_type));
1328 self.funcs.push((*sig_idx, Rc::clone(func_type)));
1329 entity
1330 }
1331 _ => panic!("a function type is required for function import"),
1332 },
1333 }
1334 }
1335
1336 wasmparser::TypeRef::Tag(wasmparser::TagType {
1337 kind,
1338 func_type_idx,
1339 }) => {
1340 imported_tags.push(wasmparser::TagType {
1341 kind: *kind,
1342 func_type_idx: *func_type_idx,
1343 });
1344 match required_types.get(*func_type_idx as usize) {
1345 None => {
1346 panic!("function type index for tag refers to a type out of bounds")
1347 }
1348 Some(ty) => match &ty.composite_type.inner {
1349 CompositeInnerType::Func(func_type) => {
1350 let tag_type = TagType {
1351 func_type_idx: *func_type_idx,
1352 func_type: Rc::clone(func_type),
1353 };
1354 let entity = EntityType::Tag(tag_type.clone());
1355 self.tags.push(tag_type);
1356 entity
1357 }
1358 _ => panic!("a function type is required for tag import"),
1359 },
1360 }
1361 }
1362
1363 wasmparser::TypeRef::Table(table_ty) => {
1364 imported_tables.push(*table_ty);
1365 let table_ty = TableType::try_from(*table_ty).unwrap();
1366 let entity = EntityType::Table(table_ty);
1367 self.tables.push(table_ty);
1368 entity
1369 }
1370
1371 wasmparser::TypeRef::Memory(memory_ty) => {
1372 imported_memories.push(*memory_ty);
1373 let memory_ty = MemoryType::from(*memory_ty);
1374 let entity = EntityType::Memory(memory_ty);
1375 self.memories.push(memory_ty);
1376 entity
1377 }
1378
1379 wasmparser::TypeRef::Global(global_ty) => {
1380 imported_globals.push(*global_ty);
1381 let global_ty = GlobalType::try_from(*global_ty).unwrap();
1382 let entity = EntityType::Global(global_ty);
1383 self.globals.push(global_ty);
1384 entity
1385 }
1386 };
1387 new_imports.push(Import {
1388 module: import.module.to_string(),
1389 field: import.name.to_string(),
1390 entity_type,
1391 });
1392 self.num_imports += 1;
1393 }
1394 self.imports.extend(new_imports);
1395 available_tags.splice(0..0, imported_tags);
1396 available_funcs.splice(0..0, imported_funcs);
1397 available_tables.splice(0..0, imported_tables);
1398 available_globals.splice(0..0, imported_globals);
1399 available_memories.splice(0..0, imported_memories);
1400
1401 for export in required_exports {
1403 let index = match export.kind {
1404 wasmparser::ExternalKind::Func => {
1405 match available_funcs.get(export.index as usize) {
1406 None => panic!("function index out of bounds"),
1407 Some(sig_idx) => match required_types.get(*sig_idx as usize) {
1408 None => panic!("signature index refers to a type out of bounds"),
1409 Some(ty) => match &ty.composite_type.inner {
1410 CompositeInnerType::Func(func_type) => {
1411 let func_index = self.funcs.len() as u32;
1412 self.funcs.push((*sig_idx, Rc::clone(func_type)));
1413 self.num_defined_funcs += 1;
1414 func_index
1415 }
1416 _ => panic!("a function type is required for function export"),
1417 },
1418 },
1419 }
1420 }
1421
1422 wasmparser::ExternalKind::Tag => match available_tags.get(export.index as usize) {
1423 None => panic!("tag index out of bounds"),
1424 Some(wasmparser::TagType { func_type_idx, .. }) => {
1425 match required_types.get(*func_type_idx as usize) {
1426 None => {
1427 panic!("function type index for tag refers to a type out of bounds")
1428 }
1429 Some(ty) => match &ty.composite_type.inner {
1430 CompositeInnerType::Func(func_type) => {
1431 let tag_index = self.tags.len() as u32;
1432 self.tags.push(TagType {
1433 func_type_idx: *func_type_idx,
1434 func_type: Rc::clone(func_type),
1435 });
1436 self.num_defined_tags += 1;
1437 tag_index
1438 }
1439 _ => panic!("a function type is required for tag export"),
1440 },
1441 }
1442 }
1443 },
1444
1445 wasmparser::ExternalKind::Table => {
1446 match available_tables.get(export.index as usize) {
1447 None => panic!("table index out of bounds"),
1448 Some(ty) => {
1449 self.add_arbitrary_table_of_type((*ty).try_into().unwrap(), u)?
1450 }
1451 }
1452 }
1453
1454 wasmparser::ExternalKind::Memory => {
1455 match available_memories.get(export.index as usize) {
1456 None => panic!("memory index out of bounds"),
1457 Some(ty) => self.add_arbitrary_memory_of_type((*ty).into())?,
1458 }
1459 }
1460
1461 wasmparser::ExternalKind::Global => {
1462 match available_globals.get(export.index as usize) {
1463 None => panic!("global index out of bounds"),
1464 Some(ty) => {
1465 self.add_arbitrary_global_of_type((*ty).try_into().unwrap(), u)?
1466 }
1467 }
1468 }
1469 };
1470 self.exports
1471 .push((export.name.to_string(), export.kind.into(), index));
1472 self.export_names.insert(export.name.to_string());
1473 }
1474
1475 Ok(())
1476 }
1477
1478 fn arbitrary_imports(&mut self, u: &mut Unstructured) -> Result<()> {
1479 if self.config.max_type_size < self.type_size {
1480 return Ok(());
1481 }
1482
1483 let mut import_strings = HashSet::new();
1484 let mut choices: Vec<fn(&mut Unstructured, &mut Module) -> Result<EntityType>> =
1485 Vec::with_capacity(5);
1486 let min = self.config.min_imports.saturating_sub(self.num_imports);
1487 let max = self.config.max_imports.saturating_sub(self.num_imports);
1488 arbitrary_loop(u, min, max, |u| {
1489 choices.clear();
1490 if self.can_add_local_or_import_tag() {
1491 choices.push(|u, m| {
1492 let ty = m.arbitrary_tag_type(u)?;
1493 Ok(EntityType::Tag(ty))
1494 });
1495 }
1496 if self.can_add_local_or_import_func() {
1497 choices.push(|u, m| {
1498 let idx = *u.choose(&m.func_types)?;
1499 let ty = m.func_type(idx).clone();
1500 Ok(EntityType::Func(idx, ty))
1501 });
1502 }
1503 if self.can_add_local_or_import_global() {
1504 choices.push(|u, m| {
1505 let ty = m.arbitrary_global_type(u)?;
1506 Ok(EntityType::Global(ty))
1507 });
1508 }
1509 if self.can_add_local_or_import_memory() {
1510 choices.push(|u, m| {
1511 let ty = arbitrary_memtype(u, m.config())?;
1512 Ok(EntityType::Memory(ty))
1513 });
1514 }
1515 if self.can_add_local_or_import_table() {
1516 choices.push(|u, m| {
1517 let ty = arbitrary_table_type(u, m.config(), Some(m))?;
1518 Ok(EntityType::Table(ty))
1519 });
1520 }
1521
1522 if choices.is_empty() {
1523 return Ok(false);
1528 }
1529
1530 let f = u.choose(&choices)?;
1533 let entity_type = f(u, self)?;
1534 let budget = self.config.max_type_size - self.type_size;
1535 if entity_type.size() + 1 > budget {
1536 return Ok(false);
1537 }
1538 self.type_size += entity_type.size() + 1;
1539
1540 let mut import_pair = unique_import_strings(1_000, u)?;
1542 if self.duplicate_imports_behavior == DuplicateImportsBehavior::Disallowed {
1543 while import_strings.contains(&import_pair) {
1544 use std::fmt::Write;
1545 write!(&mut import_pair.1, "{}", import_strings.len()).unwrap();
1546 }
1547 import_strings.insert(import_pair.clone());
1548 }
1549 let (module, field) = import_pair;
1550
1551 match &entity_type {
1554 EntityType::Tag(ty) => self.tags.push(ty.clone()),
1555 EntityType::Func(idx, ty) => self.funcs.push((*idx, ty.clone())),
1556 EntityType::Global(ty) => self.globals.push(*ty),
1557 EntityType::Table(ty) => self.tables.push(*ty),
1558 EntityType::Memory(ty) => self.memories.push(*ty),
1559 }
1560
1561 self.num_imports += 1;
1562 self.imports.push(Import {
1563 module,
1564 field,
1565 entity_type,
1566 });
1567 Ok(true)
1568 })?;
1569
1570 Ok(())
1571 }
1572
1573 fn arbitrary_imports_from_available(&mut self, u: &mut Unstructured) -> Result<bool> {
1579 let example_module = if let Some(wasm) = self.config.available_imports.take() {
1580 wasm
1581 } else {
1582 return Ok(false);
1583 };
1584
1585 #[cfg(feature = "wasmparser")]
1586 {
1587 self._arbitrary_imports_from_available(u, &example_module)?;
1588 Ok(true)
1589 }
1590 #[cfg(not(feature = "wasmparser"))]
1591 {
1592 let _ = (example_module, u);
1593 panic!("support for `available_imports` was disabled at compile time");
1594 }
1595 }
1596
1597 #[cfg(feature = "wasmparser")]
1598 fn _arbitrary_imports_from_available(
1599 &mut self,
1600 u: &mut Unstructured,
1601 example_module: &[u8],
1602 ) -> Result<()> {
1603 let mut new_recgrps = Vec::<usize>::new();
1610 let mut available_types = Vec::<SubType>::new();
1611 let mut available_imports = Vec::<wasmparser::Import>::new();
1612 let mut validator = wasmparser::Validator::new();
1613 validator
1614 .validate_all(example_module)
1615 .expect("Failed to validate `module_shape` module");
1616 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
1617 match payload.expect("could not parse the available import payload") {
1618 wasmparser::Payload::TypeSection(type_reader) => {
1619 for recgrp in type_reader {
1620 let recgrp = recgrp.expect("could not read recursive group");
1621 new_recgrps.push(recgrp.types().len());
1622 for subtype in recgrp.into_types() {
1623 let mut subtype: SubType = subtype.try_into().unwrap();
1624 if let Some(supertype_idx) = subtype.supertype {
1625 subtype.depth = available_types[supertype_idx as usize].depth + 1;
1626 }
1627 available_types.push(subtype);
1628 }
1629 }
1630 }
1631 wasmparser::Payload::ImportSection(import_reader) => {
1632 for im in import_reader {
1633 let im = im.expect("could not read import");
1634 let use_import = u.arbitrary().unwrap_or(false);
1637 if !use_import {
1638 continue;
1639 }
1640 available_imports.push(im);
1641 }
1642 }
1643 _ => {}
1644 }
1645 }
1646
1647 let mut new_imports = Vec::with_capacity(available_imports.len());
1652 for import in available_imports {
1653 let type_size_budget = self.config.max_type_size - self.type_size;
1654 let entity_type = match &import.ty {
1655 wasmparser::TypeRef::Func(sig_idx) => {
1656 if self.funcs.len() >= self.config.max_funcs {
1657 continue;
1658 } else {
1659 match available_types.get(*sig_idx as usize) {
1660 None => panic!("signature index refers to a type out of bounds"),
1661 Some(ty) => match &ty.composite_type.inner {
1662 CompositeInnerType::Func(func_type) => {
1663 let entity = EntityType::Func(*sig_idx, Rc::clone(func_type));
1664 if type_size_budget < entity.size() {
1665 continue;
1666 }
1667 self.funcs.push((*sig_idx, Rc::clone(func_type)));
1668 entity
1669 }
1670 _ => panic!("a function type is required for function import"),
1671 },
1672 }
1673 }
1674 }
1675
1676 wasmparser::TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }) => {
1677 let can_add_tag = self.tags.len() < self.config.max_tags;
1678 if !self.config.exceptions_enabled || !can_add_tag {
1679 continue;
1680 } else {
1681 match available_types.get(*func_type_idx as usize) {
1682 None => {
1683 panic!("function type index for tag refers to a type out of bounds")
1684 }
1685 Some(ty) => match &ty.composite_type.inner {
1686 CompositeInnerType::Func(func_type) => {
1687 let tag_type = TagType {
1688 func_type_idx: *func_type_idx,
1689 func_type: Rc::clone(func_type),
1690 };
1691 let entity = EntityType::Tag(tag_type.clone());
1692 if type_size_budget < entity.size() {
1693 continue;
1694 }
1695 self.tags.push(tag_type);
1696 entity
1697 }
1698 _ => panic!("a function type is required for tag import"),
1699 },
1700 }
1701 }
1702 }
1703
1704 wasmparser::TypeRef::Table(table_ty) => {
1705 let table_ty = TableType::try_from(*table_ty).unwrap();
1706 let entity = EntityType::Table(table_ty);
1707 let type_size = entity.size();
1708 if type_size_budget < type_size || !self.can_add_local_or_import_table() {
1709 continue;
1710 }
1711 self.type_size += type_size;
1712 self.tables.push(table_ty);
1713 entity
1714 }
1715
1716 wasmparser::TypeRef::Memory(memory_ty) => {
1717 let memory_ty = MemoryType::from(*memory_ty);
1718 let entity = EntityType::Memory(memory_ty);
1719 let type_size = entity.size();
1720 if type_size_budget < type_size || !self.can_add_local_or_import_memory() {
1721 continue;
1722 }
1723 self.type_size += type_size;
1724 self.memories.push(memory_ty);
1725 entity
1726 }
1727
1728 wasmparser::TypeRef::Global(global_ty) => {
1729 let global_ty = GlobalType::try_from(*global_ty).unwrap();
1730 let entity = EntityType::Global(global_ty);
1731 let type_size = entity.size();
1732 if type_size_budget < type_size || !self.can_add_local_or_import_global() {
1733 continue;
1734 }
1735 self.type_size += type_size;
1736 self.globals.push(global_ty);
1737 entity
1738 }
1739 };
1740 new_imports.push(Import {
1741 module: import.module.to_string(),
1742 field: import.name.to_string(),
1743 entity_type,
1744 });
1745 self.num_imports += 1;
1746 }
1747
1748 let mut recgrp_start_idx = self.types.len();
1750 for size in new_recgrps {
1751 self.rec_groups
1752 .push(recgrp_start_idx..recgrp_start_idx + size);
1753 recgrp_start_idx += size;
1754 }
1755 for ty in available_types {
1756 self.add_type(ty);
1757 }
1758 self.imports.extend(new_imports);
1759
1760 Ok(())
1761 }
1762
1763 fn type_of(&self, kind: ExportKind, index: u32) -> EntityType {
1764 match kind {
1765 ExportKind::Global => EntityType::Global(self.globals[index as usize]),
1766 ExportKind::Memory => EntityType::Memory(self.memories[index as usize]),
1767 ExportKind::Table => EntityType::Table(self.tables[index as usize]),
1768 ExportKind::Func => {
1769 let (_idx, ty) = &self.funcs[index as usize];
1770 EntityType::Func(u32::max_value(), ty.clone())
1771 }
1772 ExportKind::Tag => EntityType::Tag(self.tags[index as usize].clone()),
1773 }
1774 }
1775
1776 fn ty(&self, idx: u32) -> &SubType {
1777 &self.types[idx as usize]
1778 }
1779
1780 fn func_types(&self) -> impl Iterator<Item = (u32, &FuncType)> + '_ {
1781 self.func_types
1782 .iter()
1783 .copied()
1784 .map(move |type_i| (type_i, &**self.func_type(type_i)))
1785 }
1786
1787 fn func_type(&self, idx: u32) -> &Rc<FuncType> {
1788 match &self.ty(idx).composite_type.inner {
1789 CompositeInnerType::Func(f) => f,
1790 _ => panic!("types[{idx}] is not a func type"),
1791 }
1792 }
1793
1794 fn tags(&self) -> impl Iterator<Item = (u32, &TagType)> + '_ {
1795 self.tags
1796 .iter()
1797 .enumerate()
1798 .map(move |(i, ty)| (i as u32, ty))
1799 }
1800
1801 fn funcs(&self) -> impl Iterator<Item = (u32, &Rc<FuncType>)> + '_ {
1802 self.funcs
1803 .iter()
1804 .enumerate()
1805 .map(move |(i, (_, ty))| (i as u32, ty))
1806 }
1807
1808 fn has_tag_func_types(&self) -> bool {
1809 self.tag_func_types().next().is_some()
1810 }
1811
1812 fn tag_func_types(&self) -> impl Iterator<Item = u32> + '_ {
1813 self.func_types
1814 .iter()
1815 .copied()
1816 .filter(move |i| self.func_type(*i).results.is_empty())
1817 }
1818
1819 fn arbitrary_valtype(&self, u: &mut Unstructured) -> Result<ValType> {
1820 #[derive(PartialEq, Eq, PartialOrd, Ord)]
1821 enum ValTypeClass {
1822 I32,
1823 I64,
1824 F32,
1825 F64,
1826 V128,
1827 Ref,
1828 }
1829
1830 let mut val_classes: Vec<_> = self
1831 .valtypes
1832 .iter()
1833 .map(|vt| match vt {
1834 ValType::I32 => ValTypeClass::I32,
1835 ValType::I64 => ValTypeClass::I64,
1836 ValType::F32 => ValTypeClass::F32,
1837 ValType::F64 => ValTypeClass::F64,
1838 ValType::V128 => ValTypeClass::V128,
1839 ValType::Ref(_) => ValTypeClass::Ref,
1840 })
1841 .collect();
1842 val_classes.sort_unstable();
1843 val_classes.dedup();
1844
1845 match u.choose(&val_classes)? {
1846 ValTypeClass::I32 => Ok(ValType::I32),
1847 ValTypeClass::I64 => Ok(ValType::I64),
1848 ValTypeClass::F32 => Ok(ValType::F32),
1849 ValTypeClass::F64 => Ok(ValType::F64),
1850 ValTypeClass::V128 => Ok(ValType::V128),
1851 ValTypeClass::Ref => Ok(ValType::Ref(self.arbitrary_ref_type(u)?)),
1852 }
1853 }
1854
1855 fn arbitrary_global_type(&self, u: &mut Unstructured) -> Result<GlobalType> {
1856 let val_type = self.arbitrary_valtype(u)?;
1857 let shared = match val_type {
1859 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {
1860 self.arbitrary_shared(u)?
1861 }
1862 ValType::Ref(r) => self.is_shared_ref_type(r),
1863 };
1864 Ok(GlobalType {
1865 val_type,
1866 mutable: u.arbitrary()?,
1867 shared,
1868 })
1869 }
1870
1871 fn arbitrary_tag_type(&self, u: &mut Unstructured) -> Result<TagType> {
1872 let candidate_func_types: Vec<_> = self.tag_func_types().collect();
1873 arbitrary_tag_type(u, &candidate_func_types, |ty_idx| {
1874 self.func_type(ty_idx).clone()
1875 })
1876 }
1877
1878 fn arbitrary_tags(&mut self, u: &mut Unstructured) -> Result<()> {
1879 if !self.config.exceptions_enabled || !self.has_tag_func_types() {
1880 return Ok(());
1881 }
1882
1883 arbitrary_loop(u, self.config.min_tags, self.config.max_tags, |u| {
1884 if !self.can_add_local_or_import_tag() {
1885 return Ok(false);
1886 }
1887 self.tags.push(self.arbitrary_tag_type(u)?);
1888 self.num_defined_tags += 1;
1889 Ok(true)
1890 })
1891 }
1892
1893 fn arbitrary_funcs(&mut self, u: &mut Unstructured) -> Result<()> {
1894 if self.func_types.is_empty() {
1895 return Ok(());
1896 }
1897
1898 let unshared_func_types: Vec<_> = self
1903 .func_types
1904 .iter()
1905 .copied()
1906 .filter(|&i| !self.is_shared_type(i))
1907 .collect();
1908 if unshared_func_types.is_empty() {
1909 return Ok(());
1910 }
1911
1912 arbitrary_loop(u, self.config.min_funcs, self.config.max_funcs, |u| {
1913 if !self.can_add_local_or_import_func() {
1914 return Ok(false);
1915 }
1916 let max = unshared_func_types.len() - 1;
1917 let ty = unshared_func_types[u.int_in_range(0..=max)?];
1918 self.funcs.push((ty, self.func_type(ty).clone()));
1919 self.num_defined_funcs += 1;
1920 Ok(true)
1921 })
1922 }
1923
1924 fn arbitrary_tables(&mut self, u: &mut Unstructured) -> Result<()> {
1925 arbitrary_loop(
1926 u,
1927 self.config.min_tables as usize,
1928 self.config.max_tables,
1929 |u| {
1930 if !self.can_add_local_or_import_table() {
1931 return Ok(false);
1932 }
1933 let ty = arbitrary_table_type(u, self.config(), Some(self))?;
1934 self.add_arbitrary_table_of_type(ty, u)?;
1935 Ok(true)
1936 },
1937 )
1938 }
1939
1940 fn arbitrary_table_init(
1946 &mut self,
1947 u: &mut Unstructured,
1948 ty: RefType,
1949 ) -> Result<Option<ConstExpr>> {
1950 if !self.config.gc_enabled {
1951 assert!(ty.nullable);
1952 return Ok(None);
1953 }
1954 if ty.nullable && u.arbitrary()? {
1957 return Ok(None);
1958 }
1959 let expr = self.arbitrary_const_expr(ValType::Ref(ty), u, false)?;
1962 Ok(Some(expr))
1963 }
1964
1965 fn arbitrary_memories(&mut self, u: &mut Unstructured) -> Result<()> {
1966 arbitrary_loop(
1967 u,
1968 self.config.min_memories as usize,
1969 self.config.max_memories,
1970 |u| {
1971 if !self.can_add_local_or_import_memory() {
1972 return Ok(false);
1973 }
1974 let ty = arbitrary_memtype(u, self.config())?;
1975 self.add_arbitrary_memory_of_type(ty)?;
1976 Ok(true)
1977 },
1978 )
1979 }
1980
1981 fn add_arbitrary_global_of_type(
1983 &mut self,
1984 ty: GlobalType,
1985 u: &mut Unstructured,
1986 ) -> Result<u32> {
1987 let expr = self.arbitrary_const_expr(ty.val_type, u, true)?;
1988 let global_idx = self.globals.len() as u32;
1989 self.globals.push(ty);
1990 self.defined_globals.push((global_idx, expr));
1991 Ok(global_idx)
1992 }
1993
1994 fn add_arbitrary_memory_of_type(&mut self, ty: MemoryType) -> Result<u32> {
1996 let memory_idx = self.memories.len() as u32;
1997 self.num_defined_memories += 1;
1998 self.memories.push(ty);
1999 Ok(memory_idx)
2000 }
2001
2002 fn add_arbitrary_table_of_type(&mut self, ty: TableType, u: &mut Unstructured) -> Result<u32> {
2004 let expr = self.arbitrary_table_init(u, ty.element_type)?;
2005 let table_idx = self.tables.len() as u32;
2006 self.tables.push(ty);
2007 self.defined_tables.push(expr);
2008 Ok(table_idx)
2009 }
2010
2011 fn arbitrary_const_expr(
2013 &mut self,
2014 ty: ValType,
2015 u: &mut Unstructured,
2016 allow_defined_globals: bool,
2017 ) -> Result<ConstExpr> {
2018 let mut choices = mem::take(&mut self.const_expr_choices);
2019 choices.clear();
2020
2021 for i in self.globals_for_const_expr(ty, allow_defined_globals) {
2025 choices.push(Box::new(move |_, _| Ok(ConstExpr::global_get(i))));
2026 }
2027
2028 let ty = self.arbitrary_matching_val_type(u, ty)?;
2032 match ty {
2033 ValType::I32 => {
2034 choices.push(Box::new(|u, _| Ok(ConstExpr::i32_const(u.arbitrary()?))));
2035 if self.config.extended_const_enabled {
2036 choices.push(Box::new(arbitrary_extended_const));
2037 }
2038 }
2039 ValType::I64 => {
2040 choices.push(Box::new(|u, _| Ok(ConstExpr::i64_const(u.arbitrary()?))));
2041 if self.config.extended_const_enabled {
2042 choices.push(Box::new(arbitrary_extended_const));
2043 }
2044 }
2045 ValType::F32 => choices.push(Box::new(|u, _| {
2046 Ok(ConstExpr::f32_const(u.arbitrary::<f32>()?.into()))
2047 })),
2048 ValType::F64 => choices.push(Box::new(|u, _| {
2049 Ok(ConstExpr::f64_const(u.arbitrary::<f64>()?.into()))
2050 })),
2051 ValType::V128 => {
2052 choices.push(Box::new(|u, _| Ok(ConstExpr::v128_const(u.arbitrary()?))))
2053 }
2054
2055 ValType::Ref(ty) => {
2056 if ty.nullable {
2057 choices.push(Box::new(move |_, _| Ok(ConstExpr::ref_null(ty.heap_type))));
2058 }
2059
2060 match ty.heap_type {
2061 HeapType::Abstract {
2062 ty: AbstractHeapType::Func,
2063 shared,
2064 } => {
2065 let num_funcs = self
2066 .funcs
2067 .iter()
2068 .filter(|(t, _)| shared == self.is_shared_type(*t))
2069 .count();
2070 if num_funcs > 0 {
2071 let pick = u.int_in_range(0..=num_funcs - 1)?;
2072 let (i, _) = self
2073 .funcs
2074 .iter()
2075 .map(|(t, _)| *t)
2076 .enumerate()
2077 .filter(|(_, t)| shared == self.is_shared_type(*t))
2078 .nth(pick)
2079 .unwrap();
2080 choices.push(Box::new(move |_, _| Ok(ConstExpr::ref_func(i as u32))));
2081 }
2082 }
2083
2084 HeapType::Concrete(ty) => {
2085 for (i, fty) in self.funcs.iter().map(|(t, _)| *t).enumerate() {
2086 if ty != fty {
2087 continue;
2088 }
2089 choices.push(Box::new(move |_, _| Ok(ConstExpr::ref_func(i as u32))));
2090 }
2091 }
2092
2093 _ => {}
2096 }
2097 }
2098 }
2099
2100 let f = u.choose(&choices)?;
2101 let ret = f(u, ty);
2102 self.const_expr_choices = choices;
2103 return ret;
2104
2105 fn arbitrary_extended_const(u: &mut Unstructured<'_>, ty: ValType) -> Result<ConstExpr> {
2113 use wasm_encoder::Instruction::*;
2114
2115 assert!(ty == ValType::I32 || ty == ValType::I64);
2118 let add = if ty == ValType::I32 { I32Add } else { I64Add };
2119 let sub = if ty == ValType::I32 { I32Sub } else { I64Sub };
2120 let mul = if ty == ValType::I32 { I32Mul } else { I64Mul };
2121 let const_: fn(&mut Unstructured<'_>) -> Result<wasm_encoder::Instruction<'static>> =
2122 if ty == ValType::I32 {
2123 |u| u.arbitrary().map(I32Const)
2124 } else {
2125 |u| u.arbitrary().map(I64Const)
2126 };
2127
2128 let mut instrs = Vec::new();
2133 let mut needed = 1;
2134 while needed > 0 {
2135 let choice = if u.is_empty() || instrs.len() > 10 {
2139 0
2140 } else {
2141 u.int_in_range(0..=3)?
2142 };
2143 match choice {
2144 0 => {
2145 instrs.push(const_(u)?);
2146 needed -= 1;
2147 }
2148 1 => {
2149 instrs.push(add.clone());
2150 needed += 1;
2151 }
2152 2 => {
2153 instrs.push(sub.clone());
2154 needed += 1;
2155 }
2156 3 => {
2157 instrs.push(mul.clone());
2158 needed += 1;
2159 }
2160 _ => unreachable!(),
2161 }
2162 }
2163 Ok(ConstExpr::extended(instrs.into_iter().rev()))
2164 }
2165 }
2166
2167 fn arbitrary_globals(&mut self, u: &mut Unstructured) -> Result<()> {
2168 arbitrary_loop(u, self.config.min_globals, self.config.max_globals, |u| {
2169 if !self.can_add_local_or_import_global() {
2170 return Ok(false);
2171 }
2172
2173 let ty = self.arbitrary_global_type(u)?;
2174 self.add_arbitrary_global_of_type(ty, u)?;
2175
2176 Ok(true)
2177 })
2178 }
2179
2180 fn required_exports(&mut self, u: &mut Unstructured) -> Result<bool> {
2181 let example_module = if let Some(wasm) = self.config.exports.clone() {
2182 wasm
2183 } else {
2184 return Ok(false);
2185 };
2186
2187 #[cfg(feature = "wasmparser")]
2188 {
2189 self._required_exports(u, &example_module)?;
2190 Ok(true)
2191 }
2192 #[cfg(not(feature = "wasmparser"))]
2193 {
2194 let _ = (example_module, u);
2195 panic!("support for `exports` was disabled at compile time");
2196 }
2197 }
2198
2199 #[cfg(feature = "wasmparser")]
2200 fn _required_exports(&mut self, u: &mut Unstructured, example_module: &[u8]) -> Result<()> {
2201 let mut required_exports: Vec<wasmparser::Export> = vec![];
2202 let mut validator = wasmparser::Validator::new();
2203 let exports_types = validator
2204 .validate_all(&example_module)
2205 .expect("Failed to validate `exports` Wasm");
2206 for payload in wasmparser::Parser::new(0).parse_all(&example_module) {
2207 match payload.expect("Failed to read `exports` Wasm") {
2208 wasmparser::Payload::ExportSection(export_reader) => {
2209 required_exports = export_reader
2210 .into_iter()
2211 .collect::<Result<_, _>>()
2212 .expect("Failed to read `exports` export section");
2213 }
2214 _ => {}
2215 }
2216 }
2217
2218 let exports_types = exports_types.as_ref();
2220 let check_and_get_func_type =
2221 |id: wasmparser::types::CoreTypeId| -> (Rc<FuncType>, SubType) {
2222 let subtype = exports_types.get(id).unwrap_or_else(|| {
2223 panic!("Unable to get subtype for {id:?} in `exports` Wasm")
2224 });
2225 match &subtype.composite_type.inner {
2226 wasmparser::CompositeInnerType::Func(func_type) => {
2227 assert!(
2228 subtype.is_final,
2229 "Subtype {subtype:?} from `exports` Wasm is not final"
2230 );
2231 assert!(
2232 subtype.supertype_idx.is_none(),
2233 "Subtype {subtype:?} from `exports` Wasm has non-empty supertype"
2234 );
2235 let func_type = Rc::new(FuncType {
2236 params: func_type
2237 .params()
2238 .iter()
2239 .copied()
2240 .map(|t| t.try_into().unwrap())
2241 .collect(),
2242 results: func_type
2243 .results()
2244 .iter()
2245 .copied()
2246 .map(|t| t.try_into().unwrap())
2247 .collect(),
2248 });
2249 let subtype = SubType {
2250 is_final: true,
2251 supertype: None,
2252 depth: 1,
2253 composite_type: CompositeType::new_func(
2254 Rc::clone(&func_type),
2255 subtype.composite_type.shared,
2256 ),
2257 };
2258 (func_type, subtype)
2259 }
2260 _ => panic!(
2261 "Unable to handle type {:?} from `exports` Wasm",
2262 subtype.composite_type
2263 ),
2264 }
2265 };
2266 for export in required_exports {
2267 let new_index = match exports_types
2268 .entity_type_from_export(&export)
2269 .unwrap_or_else(|| {
2270 panic!("Unable to get type from export {export:?} in `exports` Wasm",)
2271 }) {
2272 wasmparser::types::EntityType::Func(id) => {
2274 let (func_type, subtype) = check_and_get_func_type(id);
2275 self.rec_groups.push(self.types.len()..self.types.len() + 1);
2276 let type_index = self.add_type(subtype);
2277 let func_index = self.funcs.len() as u32;
2278 self.funcs.push((type_index, func_type));
2279 self.num_defined_funcs += 1;
2280 func_index
2281 }
2282 wasmparser::types::EntityType::Global(global_type) => {
2284 self.add_arbitrary_global_of_type(global_type.try_into().unwrap(), u)?
2285 }
2286 wasmparser::types::EntityType::Memory(memory_type) => {
2288 self.add_arbitrary_memory_of_type(memory_type.into())?
2289 }
2290 wasmparser::types::EntityType::Table(table_type) => {
2292 self.add_arbitrary_table_of_type(table_type.try_into().unwrap(), u)?
2293 }
2294 wasmparser::types::EntityType::Tag(id) => {
2296 let (func_type, subtype) = check_and_get_func_type(id);
2297 self.rec_groups.push(self.types.len()..self.types.len() + 1);
2298 let type_index = self.add_type(subtype);
2299 let tag_index = self.tags.len() as u32;
2300 self.tags.push(TagType {
2301 func_type_idx: type_index,
2302 func_type: func_type,
2303 });
2304 self.num_defined_tags += 1;
2305 tag_index
2306 }
2307 };
2308 self.exports
2309 .push((export.name.to_string(), export.kind.into(), new_index));
2310 self.export_names.insert(export.name.to_string());
2311 }
2312
2313 Ok(())
2314 }
2315
2316 fn arbitrary_exports(&mut self, u: &mut Unstructured) -> Result<()> {
2317 if self.config.max_type_size < self.type_size && !self.config.export_everything {
2318 return Ok(());
2319 }
2320
2321 let mut choices: Vec<Vec<(ExportKind, u32)>> = Vec::with_capacity(6);
2323 choices.push(
2324 (0..self.funcs.len())
2325 .map(|i| (ExportKind::Func, i as u32))
2326 .collect(),
2327 );
2328 choices.push(
2329 (0..self.tables.len())
2330 .map(|i| (ExportKind::Table, i as u32))
2331 .collect(),
2332 );
2333 choices.push(
2334 (0..self.memories.len())
2335 .map(|i| (ExportKind::Memory, i as u32))
2336 .collect(),
2337 );
2338 choices.push(
2339 (0..self.globals.len())
2340 .map(|i| (ExportKind::Global, i as u32))
2341 .collect(),
2342 );
2343
2344 if self.config.export_everything {
2347 for choices_by_kind in choices {
2348 for (kind, idx) in choices_by_kind {
2349 let name = unique_string(1_000, &mut self.export_names, u)?;
2350 self.add_arbitrary_export(name, kind, idx)?;
2351 }
2352 }
2353 return Ok(());
2354 }
2355
2356 arbitrary_loop(u, self.config.min_exports, self.config.max_exports, |u| {
2357 let max_size = self.config.max_type_size - self.type_size;
2363 for list in choices.iter_mut() {
2364 list.retain(|(kind, idx)| self.type_of(*kind, *idx).size() + 1 < max_size);
2365 }
2366 choices.retain(|list| !list.is_empty());
2367 if choices.is_empty() {
2368 return Ok(false);
2369 }
2370
2371 let name = unique_string(1_000, &mut self.export_names, u)?;
2374 let list = u.choose(&choices)?;
2375 let (kind, idx) = *u.choose(list)?;
2376 self.add_arbitrary_export(name, kind, idx)?;
2377 Ok(true)
2378 })
2379 }
2380
2381 fn add_arbitrary_export(&mut self, name: String, kind: ExportKind, idx: u32) -> Result<()> {
2382 let ty = self.type_of(kind, idx);
2383 self.type_size += 1 + ty.size();
2384 if self.type_size <= self.config.max_type_size {
2385 self.exports.push((name, kind, idx));
2386 Ok(())
2387 } else {
2388 Err(arbitrary::Error::IncorrectFormat)
2392 }
2393 }
2394
2395 fn arbitrary_start(&mut self, u: &mut Unstructured) -> Result<()> {
2396 if !self.config.allow_start_export {
2397 return Ok(());
2398 }
2399
2400 let mut choices = Vec::with_capacity(self.funcs.len());
2401
2402 for (func_idx, ty) in self.funcs() {
2403 if ty.params.is_empty() && ty.results.is_empty() {
2404 choices.push(func_idx);
2405 }
2406 }
2407
2408 if !choices.is_empty() && u.arbitrary().unwrap_or(false) {
2409 let f = *u.choose(&choices)?;
2410 self.start = Some(f);
2411 }
2412
2413 Ok(())
2414 }
2415
2416 fn arbitrary_elems(&mut self, u: &mut Unstructured) -> Result<()> {
2417 let mut global_i32 = vec![];
2419 let mut global_i64 = vec![];
2420 if !self.config.disallow_traps {
2421 for i in self.globals_for_const_expr(ValType::I32, true) {
2422 global_i32.push(i);
2423 }
2424 for i in self.globals_for_const_expr(ValType::I64, true) {
2425 global_i64.push(i);
2426 }
2427 }
2428 let disallow_traps = self.config.disallow_traps;
2429 let arbitrary_active_elem =
2430 |u: &mut Unstructured, min_mem_size: u64, table: Option<u32>, table_ty: &TableType| {
2431 let global_choices = if table_ty.table64 {
2432 &global_i64
2433 } else {
2434 &global_i32
2435 };
2436 let (offset, max_size_hint) = if !global_choices.is_empty() && u.arbitrary()? {
2437 let g = u.choose(&global_choices)?;
2438 (Offset::Global(*g), None)
2439 } else {
2440 let max_mem_size = if disallow_traps {
2441 table_ty.minimum
2442 } else if table_ty.table64 {
2443 u64::MAX
2444 } else {
2445 u64::from(u32::MAX)
2446 };
2447 let offset = arbitrary_offset(u, min_mem_size, max_mem_size, 0)?;
2448 let max_size_hint = if disallow_traps
2449 || (offset <= min_mem_size
2450 && u.int_in_range(0..=CHANCE_OFFSET_INBOUNDS)? != 0)
2451 {
2452 Some(min_mem_size - offset)
2453 } else {
2454 None
2455 };
2456
2457 let offset = if table_ty.table64 {
2458 Offset::Const64(offset as i64)
2459 } else {
2460 Offset::Const32(offset as i32)
2461 };
2462 (offset, max_size_hint)
2463 };
2464 Ok((ElementKind::Active { table, offset }, max_size_hint))
2465 };
2466
2467 type GenElemSegment<'a> =
2471 dyn Fn(&mut Unstructured) -> Result<(ElementKind, Option<u64>)> + 'a;
2472 let mut choices: Vec<Box<GenElemSegment>> = Vec::new();
2473
2474 if self.config.bulk_memory_enabled {
2477 choices.push(Box::new(|_| Ok((ElementKind::Passive, None))));
2478 choices.push(Box::new(|_| Ok((ElementKind::Declared, None))));
2479 }
2480
2481 for (i, ty) in self.tables.iter().enumerate() {
2482 if ty.minimum == 0 && u.int_in_range(0..=CHANCE_SEGMENT_ON_EMPTY)? != 0 {
2487 continue;
2488 }
2489
2490 let minimum = ty.minimum;
2491 let ty = *ty;
2494 if i == 0 && ty.element_type == RefType::FUNCREF {
2495 choices.push(Box::new(move |u| {
2496 arbitrary_active_elem(u, minimum, None, &ty)
2497 }));
2498 }
2499 if self.config.bulk_memory_enabled {
2500 let idx = Some(i as u32);
2501 choices.push(Box::new(move |u| {
2502 arbitrary_active_elem(u, minimum, idx, &ty)
2503 }));
2504 }
2505 }
2506
2507 if choices.is_empty() {
2508 return Ok(());
2509 }
2510
2511 arbitrary_loop(
2512 u,
2513 self.config.min_element_segments,
2514 self.config.max_element_segments,
2515 |u| {
2516 let (kind, max_size_hint) = u.choose(&choices)?(u)?;
2519 let max = max_size_hint
2520 .map(|i| usize::try_from(i).unwrap())
2521 .unwrap_or_else(|| self.config.max_elements);
2522
2523 let ty = match kind {
2527 ElementKind::Passive | ElementKind::Declared => self.arbitrary_ref_type(u)?,
2528 ElementKind::Active { table, .. } => {
2529 let idx = table.unwrap_or(0);
2530 self.arbitrary_matching_ref_type(u, self.tables[idx as usize].element_type)?
2531 }
2532 };
2533
2534 let can_use_function_list = ty == RefType::FUNCREF;
2538 if !self.config.reference_types_enabled {
2539 assert!(can_use_function_list);
2540 }
2541
2542 let mut func_candidates = Vec::new();
2545 if can_use_function_list {
2546 match ty.heap_type {
2547 HeapType::Abstract {
2548 ty: AbstractHeapType::Func,
2549 ..
2550 } => {
2551 func_candidates.extend(0..self.funcs.len() as u32);
2552 }
2553 HeapType::Concrete(ty) => {
2554 for (i, (fty, _)) in self.funcs.iter().enumerate() {
2555 if *fty == ty {
2556 func_candidates.push(i as u32);
2557 }
2558 }
2559 }
2560 _ => {}
2561 }
2562 }
2563
2564 let items = if !self.config.reference_types_enabled
2569 || (can_use_function_list && u.arbitrary()?)
2570 {
2571 let mut init = vec![];
2572 if func_candidates.len() > 0 {
2573 arbitrary_loop(u, self.config.min_elements, max, |u| {
2574 let func_idx = *u.choose(&func_candidates)?;
2575 init.push(func_idx);
2576 Ok(true)
2577 })?;
2578 }
2579 Elements::Functions(init)
2580 } else {
2581 let mut init = vec![];
2582 arbitrary_loop(u, self.config.min_elements, max, |u| {
2583 init.push(self.arbitrary_const_expr(ValType::Ref(ty), u, true)?);
2584 Ok(true)
2585 })?;
2586 Elements::Expressions(init)
2587 };
2588
2589 self.elems.push(ElementSegment { kind, ty, items });
2590 Ok(true)
2591 },
2592 )
2593 }
2594
2595 fn arbitrary_code(&mut self, u: &mut Unstructured) -> Result<()> {
2596 self.compute_interesting_values();
2597
2598 self.code.reserve(self.num_defined_funcs);
2599 let mut allocs = CodeBuilderAllocations::new(
2600 self,
2601 self.config.exports.is_some() || self.config.module_shape.is_some(),
2602 );
2603 for (idx, ty) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() {
2604 let shared = self.is_shared_type(*idx);
2605 let body = self.arbitrary_func_body(u, ty, &mut allocs, shared)?;
2606 self.code.push(body);
2607 }
2608 allocs.finish(u, self)?;
2609 Ok(())
2610 }
2611
2612 fn arbitrary_func_body(
2613 &self,
2614 u: &mut Unstructured,
2615 ty: &FuncType,
2616 allocs: &mut CodeBuilderAllocations,
2617 shared: bool,
2618 ) -> Result<Code> {
2619 let mut locals = self.arbitrary_locals(u)?;
2620 let builder = allocs.builder(ty, &mut locals, shared);
2621 let instructions = if self.config.allow_invalid_funcs && u.arbitrary().unwrap_or(false) {
2622 Instructions::Arbitrary(arbitrary_vec_u8(u)?)
2623 } else {
2624 Instructions::Generated(builder.arbitrary(u, self)?)
2625 };
2626
2627 Ok(Code {
2628 locals,
2629 instructions,
2630 })
2631 }
2632
2633 fn arbitrary_locals(&self, u: &mut Unstructured) -> Result<Vec<ValType>> {
2634 let mut ret = Vec::new();
2635 arbitrary_loop(u, 0, 100, |u| {
2636 ret.push(self.arbitrary_valtype(u)?);
2637 Ok(true)
2638 })?;
2639 Ok(ret)
2640 }
2641
2642 fn arbitrary_data(&mut self, u: &mut Unstructured) -> Result<()> {
2643 let memories = self.memories.len() as u32;
2646 if memories == 0 && !self.config.bulk_memory_enabled {
2647 return Ok(());
2648 }
2649 let disallow_traps = self.config.disallow_traps;
2650 let mut choices32: Vec<Box<dyn Fn(&mut Unstructured, u64, usize) -> Result<Offset>>> =
2651 vec![];
2652 choices32.push(Box::new(|u, min_size, data_len| {
2653 let min = u32::try_from(min_size.saturating_mul(64 * 1024))
2654 .unwrap_or(u32::MAX)
2655 .into();
2656 let max = if disallow_traps { min } else { u32::MAX.into() };
2657 Ok(Offset::Const32(
2658 arbitrary_offset(u, min, max, data_len)? as i32
2659 ))
2660 }));
2661 let mut choices64: Vec<Box<dyn Fn(&mut Unstructured, u64, usize) -> Result<Offset>>> =
2662 vec![];
2663 choices64.push(Box::new(|u, min_size, data_len| {
2664 let min = min_size.saturating_mul(64 * 1024);
2665 let max = if disallow_traps { min } else { u64::MAX };
2666 Ok(Offset::Const64(
2667 arbitrary_offset(u, min, max, data_len)? as i64
2668 ))
2669 }));
2670 if !self.config.disallow_traps {
2671 for i in self.globals_for_const_expr(ValType::I32, true) {
2672 choices32.push(Box::new(move |_, _, _| Ok(Offset::Global(i))));
2673 }
2674 for i in self.globals_for_const_expr(ValType::I64, true) {
2675 choices64.push(Box::new(move |_, _, _| Ok(Offset::Global(i))));
2676 }
2677 }
2678
2679 let mut memories = Vec::new();
2685 for (i, mem) in self.memories.iter().enumerate() {
2686 if mem.minimum > 0 || u.int_in_range(0..=CHANCE_SEGMENT_ON_EMPTY)? == 0 {
2687 memories.push(i as u32);
2688 }
2689 }
2690
2691 if memories.is_empty() && !self.config.bulk_memory_enabled {
2695 return Ok(());
2696 }
2697
2698 arbitrary_loop(
2699 u,
2700 self.config.min_data_segments,
2701 self.config.max_data_segments,
2702 |u| {
2703 let mut init: Vec<u8> = u.arbitrary()?;
2704
2705 let kind =
2710 if self.config.bulk_memory_enabled && (memories.is_empty() || u.arbitrary()?) {
2711 DataSegmentKind::Passive
2712 } else {
2713 let memory_index = *u.choose(&memories)?;
2714 let mem = &self.memories[memory_index as usize];
2715 let f = if mem.memory64 {
2716 u.choose(&choices64)?
2717 } else {
2718 u.choose(&choices32)?
2719 };
2720 let mut offset = f(u, mem.minimum, init.len())?;
2721
2722 if self.config.disallow_traps {
2727 let max_size = (u64::MAX / 64 / 1024).min(mem.minimum) * 64 * 1024;
2728 init.truncate(max_size as usize);
2729 let max_offset = max_size - init.len() as u64;
2730 match &mut offset {
2731 Offset::Const32(x) => {
2732 *x = (*x as u64).min(max_offset) as i32;
2733 }
2734 Offset::Const64(x) => {
2735 *x = (*x as u64).min(max_offset) as i64;
2736 }
2737 Offset::Global(_) => unreachable!(),
2738 }
2739 }
2740 DataSegmentKind::Active {
2741 offset,
2742 memory_index,
2743 }
2744 };
2745 self.data.push(DataSegment { kind, init });
2746 Ok(true)
2747 },
2748 )
2749 }
2750
2751 fn params_results(&self, ty: &BlockType) -> (Vec<ValType>, Vec<ValType>) {
2752 match ty {
2753 BlockType::Empty => (vec![], vec![]),
2754 BlockType::Result(t) => (vec![], vec![*t]),
2755 BlockType::FunctionType(ty) => {
2756 let ty = self.func_type(*ty);
2757 (ty.params.to_vec(), ty.results.to_vec())
2758 }
2759 }
2760 }
2761
2762 fn globals_for_const_expr(
2765 &self,
2766 ty: ValType,
2767 allow_defined_globals: bool,
2768 ) -> impl Iterator<Item = u32> + '_ {
2769 let num_imported_globals = self.globals.len() - self.defined_globals.len();
2772 let max_global = if self.config.gc_enabled && allow_defined_globals {
2773 self.globals.len()
2774 } else {
2775 num_imported_globals
2776 };
2777
2778 self.globals[..max_global]
2779 .iter()
2780 .enumerate()
2781 .filter_map(move |(i, g)| {
2782 if !g.mutable && self.val_type_is_sub_type(g.val_type, ty) {
2786 Some(i as u32)
2787 } else {
2788 None
2789 }
2790 })
2791 }
2792
2793 fn compute_interesting_values(&mut self) {
2794 debug_assert!(self.interesting_values32.is_empty());
2795 debug_assert!(self.interesting_values64.is_empty());
2796
2797 let mut interesting_values32 = HashSet::new();
2798 let mut interesting_values64 = HashSet::new();
2799
2800 let mut interesting = |val: u64| {
2801 interesting_values32.insert(val as u32);
2802 interesting_values64.insert(val);
2803 };
2804
2805 interesting(0);
2807
2808 interesting(u8::MAX as _);
2810 interesting(u16::MAX as _);
2811 interesting(u32::MAX as _);
2812 interesting(u64::MAX);
2813
2814 interesting(i8::MIN as _);
2816 interesting(i16::MIN as _);
2817 interesting(i32::MIN as _);
2818 interesting(i64::MIN as _);
2819
2820 for i in 0..64 {
2821 interesting(1 << i);
2823
2824 interesting(!(1 << i));
2826
2827 interesting((1 << i) - 1);
2829
2830 interesting(((1_i64 << 63) >> i) as _);
2832 }
2833
2834 for pattern in [0b01010101, 0b00010001, 0b00010001, 0b00000001] {
2836 for b in [pattern, !pattern] {
2837 interesting(u64::from_ne_bytes([b, b, b, b, b, b, b, b]));
2838 }
2839 }
2840
2841 let mut interesting_f64 = |x: f64| interesting(x.to_bits());
2843 interesting_f64(0.0);
2844 interesting_f64(-0.0);
2845 interesting_f64(f64::INFINITY);
2846 interesting_f64(f64::NEG_INFINITY);
2847 interesting_f64(f64::EPSILON);
2848 interesting_f64(-f64::EPSILON);
2849 interesting_f64(f64::MIN);
2850 interesting_f64(f64::MIN_POSITIVE);
2851 interesting_f64(f64::MAX);
2852 interesting_f64(f64::NAN);
2853 let mut interesting_f32 = |x: f32| interesting(x.to_bits() as _);
2854 interesting_f32(0.0);
2855 interesting_f32(-0.0);
2856 interesting_f32(f32::INFINITY);
2857 interesting_f32(f32::NEG_INFINITY);
2858 interesting_f32(f32::EPSILON);
2859 interesting_f32(-f32::EPSILON);
2860 interesting_f32(f32::MIN);
2861 interesting_f32(f32::MIN_POSITIVE);
2862 interesting_f32(f32::MAX);
2863 interesting_f32(f32::NAN);
2864
2865 for t in self.tables.iter() {
2867 interesting(t.minimum as _);
2868 if let Some(x) = t.minimum.checked_add(1) {
2869 interesting(x as _);
2870 }
2871
2872 if let Some(x) = t.maximum {
2873 interesting(x as _);
2874 if let Some(y) = x.checked_add(1) {
2875 interesting(y as _);
2876 }
2877 }
2878 }
2879
2880 for m in self.memories.iter() {
2882 let min = m.minimum.saturating_mul(crate::page_size(m).into());
2883 interesting(min);
2884 for i in 0..5 {
2885 if let Some(x) = min.checked_add(1 << i) {
2886 interesting(x);
2887 }
2888 if let Some(x) = min.checked_sub(1 << i) {
2889 interesting(x);
2890 }
2891 }
2892
2893 if let Some(max) = m.maximum {
2894 let max = max.saturating_mul(crate::page_size(m).into());
2895 interesting(max);
2896 for i in 0..5 {
2897 if let Some(x) = max.checked_add(1 << i) {
2898 interesting(x);
2899 }
2900 if let Some(x) = max.checked_sub(1 << i) {
2901 interesting(x);
2902 }
2903 }
2904 }
2905 }
2906
2907 self.interesting_values32.extend(interesting_values32);
2908 self.interesting_values64.extend(interesting_values64);
2909
2910 self.interesting_values32.sort();
2912 self.interesting_values64.sort();
2913 }
2914
2915 fn arbitrary_const_instruction(
2916 &self,
2917 ty: ValType,
2918 u: &mut Unstructured<'_>,
2919 ) -> Result<Instruction> {
2920 debug_assert!(self.interesting_values32.len() > 0);
2921 debug_assert!(self.interesting_values64.len() > 0);
2922 match ty {
2923 ValType::I32 => Ok(Instruction::I32Const(if u.arbitrary()? {
2924 *u.choose(&self.interesting_values32)? as i32
2925 } else {
2926 u.arbitrary()?
2927 })),
2928 ValType::I64 => Ok(Instruction::I64Const(if u.arbitrary()? {
2929 *u.choose(&self.interesting_values64)? as i64
2930 } else {
2931 u.arbitrary()?
2932 })),
2933 ValType::F32 => Ok(Instruction::F32Const(if u.arbitrary()? {
2934 f32::from_bits(*u.choose(&self.interesting_values32)?).into()
2935 } else {
2936 u.arbitrary::<f32>()?.into()
2937 })),
2938 ValType::F64 => Ok(Instruction::F64Const(if u.arbitrary()? {
2939 f64::from_bits(*u.choose(&self.interesting_values64)?).into()
2940 } else {
2941 u.arbitrary::<f64>()?.into()
2942 })),
2943 ValType::V128 => Ok(Instruction::V128Const(if u.arbitrary()? {
2944 let upper = (*u.choose(&self.interesting_values64)? as i128) << 64;
2945 let lower = *u.choose(&self.interesting_values64)? as i128;
2946 upper | lower
2947 } else {
2948 u.arbitrary()?
2949 })),
2950 ValType::Ref(ty) => {
2951 assert!(ty.nullable);
2952 Ok(Instruction::RefNull(ty.heap_type))
2953 }
2954 }
2955 }
2956
2957 fn propagate_shared<T>(&mut self, must_share: bool, mut f: impl FnMut(&mut Self) -> T) -> T {
2958 let tmp = mem::replace(&mut self.must_share, must_share);
2959 let result = f(self);
2960 self.must_share = tmp;
2961 result
2962 }
2963
2964 fn arbitrary_shared(&self, u: &mut Unstructured) -> Result<bool> {
2965 if self.must_share {
2966 Ok(true)
2967 } else {
2968 Ok(self.config.shared_everything_threads_enabled && u.ratio(1, 4)?)
2969 }
2970 }
2971
2972 fn is_shared_ref_type(&self, ty: RefType) -> bool {
2973 match ty.heap_type {
2974 HeapType::Abstract { shared, .. } => shared,
2975 HeapType::Concrete(i) => self.types[i as usize].composite_type.shared,
2976 }
2977 }
2978
2979 fn is_shared_type(&self, index: u32) -> bool {
2980 let index = usize::try_from(index).unwrap();
2981 let ty = self.types.get(index).unwrap();
2982 ty.composite_type.shared
2983 }
2984}
2985
2986pub(crate) fn arbitrary_limits64(
2987 u: &mut Unstructured,
2988 min_minimum: Option<u64>,
2989 max_minimum: u64,
2990 max_required: bool,
2991 max_inbounds: u64,
2992) -> Result<(u64, Option<u64>)> {
2993 assert!(
2994 min_minimum.unwrap_or(0) <= max_minimum,
2995 "{} <= {max_minimum}",
2996 min_minimum.unwrap_or(0),
2997 );
2998 assert!(
2999 min_minimum.unwrap_or(0) <= max_inbounds,
3000 "{} <= {max_inbounds}",
3001 min_minimum.unwrap_or(0),
3002 );
3003
3004 let min = gradually_grow(u, min_minimum.unwrap_or(0), max_inbounds, max_minimum)?;
3005 assert!(min <= max_minimum, "{min} <= {max_minimum}");
3006
3007 let max = if max_required || u.arbitrary().unwrap_or(false) {
3008 Some(u.int_in_range(min..=max_minimum)?)
3009 } else {
3010 None
3011 };
3012 assert!(min <= max.unwrap_or(min), "{min} <= {}", max.unwrap_or(min));
3013
3014 Ok((min, max))
3015}
3016
3017pub(crate) fn configured_valtypes(config: &Config) -> Vec<ValType> {
3018 let mut valtypes = Vec::with_capacity(25);
3019 valtypes.push(ValType::I32);
3020 valtypes.push(ValType::I64);
3021 if config.allow_floats {
3022 valtypes.push(ValType::F32);
3023 valtypes.push(ValType::F64);
3024 }
3025 if config.simd_enabled {
3026 valtypes.push(ValType::V128);
3027 }
3028 if config.gc_enabled && config.reference_types_enabled {
3029 for nullable in [
3030 true,
3037 ] {
3038 use AbstractHeapType::*;
3039 let abs_ref_types = [
3040 Any, Eq, I31, Array, Struct, None, Func, NoFunc, Extern, NoExtern,
3041 ];
3042 valtypes.extend(
3043 abs_ref_types
3044 .iter()
3045 .map(|&ty| ValType::Ref(RefType::new_abstract(ty, nullable, false))),
3046 );
3047 if config.shared_everything_threads_enabled {
3048 valtypes.extend(
3049 abs_ref_types
3050 .iter()
3051 .map(|&ty| ValType::Ref(RefType::new_abstract(ty, nullable, true))),
3052 );
3053 }
3054 }
3055 } else if config.reference_types_enabled {
3056 valtypes.push(ValType::EXTERNREF);
3057 valtypes.push(ValType::FUNCREF);
3058 }
3059 valtypes
3060}
3061
3062pub(crate) fn arbitrary_table_type(
3063 u: &mut Unstructured,
3064 config: &Config,
3065 module: Option<&Module>,
3066) -> Result<TableType> {
3067 let table64 = config.memory64_enabled && u.arbitrary()?;
3068 let max_inbounds = 10_000;
3071 let min_elements = if config.disallow_traps { Some(1) } else { None };
3072 let max_elements = min_elements.unwrap_or(0).max(config.max_table_elements);
3073 let (minimum, maximum) = arbitrary_limits64(
3074 u,
3075 min_elements,
3076 max_elements,
3077 config.table_max_size_required,
3078 max_inbounds.min(max_elements),
3079 )?;
3080 if config.disallow_traps {
3081 assert!(minimum > 0);
3082 }
3083 let element_type = match module {
3084 Some(module) => module.arbitrary_ref_type(u)?,
3085 None => RefType::FUNCREF,
3086 };
3087
3088 let shared = match module {
3090 Some(module) => module.is_shared_ref_type(element_type),
3091 None => false,
3092 };
3093
3094 Ok(TableType {
3095 element_type,
3096 minimum,
3097 maximum,
3098 table64,
3099 shared,
3100 })
3101}
3102
3103pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &Config) -> Result<MemoryType> {
3104 let shared = config.threads_enabled && u.ratio(1, 4)?;
3107
3108 let memory64 = config.memory64_enabled && u.arbitrary()?;
3109 let page_size_log2 = if config.custom_page_sizes_enabled && u.arbitrary()? {
3110 Some(if u.arbitrary()? { 0 } else { 16 })
3111 } else {
3112 None
3113 };
3114
3115 let min_pages = if config.disallow_traps { Some(1) } else { None };
3116 let max_pages = min_pages.unwrap_or(0).max(if memory64 {
3117 u64::try_from(config.max_memory64_bytes >> page_size_log2.unwrap_or(16))
3118 .unwrap_or(u64::MAX)
3122 } else {
3123 u32::try_from(config.max_memory32_bytes >> page_size_log2.unwrap_or(16))
3124 .unwrap_or(u32::MAX)
3127 .into()
3128 });
3129
3130 let max_all_mems_in_bytes = 1 << 30;
3132 let max_this_mem_in_bytes = max_all_mems_in_bytes / u64::try_from(config.max_memories).unwrap();
3133 let max_inbounds = max_this_mem_in_bytes >> page_size_log2.unwrap_or(16);
3134 let max_inbounds = max_inbounds.clamp(min_pages.unwrap_or(0), max_pages);
3135
3136 let (minimum, maximum) = arbitrary_limits64(
3137 u,
3138 min_pages,
3139 max_pages,
3140 config.memory_max_size_required || shared,
3141 max_inbounds,
3142 )?;
3143
3144 Ok(MemoryType {
3145 minimum,
3146 maximum,
3147 memory64,
3148 shared,
3149 page_size_log2,
3150 })
3151}
3152
3153pub(crate) fn arbitrary_tag_type(
3154 u: &mut Unstructured,
3155 candidate_func_types: &[u32],
3156 get_func_type: impl FnOnce(u32) -> Rc<FuncType>,
3157) -> Result<TagType> {
3158 let max = candidate_func_types.len() - 1;
3159 let ty = candidate_func_types[u.int_in_range(0..=max)?];
3160 Ok(TagType {
3161 func_type_idx: ty,
3162 func_type: get_func_type(ty),
3163 })
3164}
3165
3166fn gradually_grow(u: &mut Unstructured, min: u64, max_inbounds: u64, max: u64) -> Result<u64> {
3174 if min == max {
3175 return Ok(min);
3176 }
3177 let x = {
3178 let min = min as f64;
3179 let max = max as f64;
3180 let max_inbounds = max_inbounds as f64;
3181 let x = u.arbitrary::<u32>()?;
3182 let x = f64::from(x);
3183 let x = map_custom(
3184 x,
3185 f64::from(u32::MIN)..f64::from(u32::MAX),
3186 min..max_inbounds,
3187 min..max,
3188 );
3189 assert!(min <= x, "{min} <= {x}");
3190 assert!(x <= max, "{x} <= {max}");
3191 x.round() as u64
3192 };
3193
3194 return Ok(x.clamp(min, max));
3197
3198 fn map_custom(
3205 value: f64,
3206 input: Range<f64>,
3207 output_inbounds: Range<f64>,
3208 output: Range<f64>,
3209 ) -> f64 {
3210 assert!(!value.is_nan(), "{}", value);
3211 assert!(value.is_finite(), "{}", value);
3212 assert!(input.start < input.end, "{} < {}", input.start, input.end);
3213 assert!(
3214 output.start < output.end,
3215 "{} < {}",
3216 output.start,
3217 output.end
3218 );
3219 assert!(value >= input.start, "{} >= {}", value, input.start);
3220 assert!(value <= input.end, "{} <= {}", value, input.end);
3221 assert!(
3222 output.start <= output_inbounds.start,
3223 "{} <= {}",
3224 output.start,
3225 output_inbounds.start
3226 );
3227 assert!(
3228 output_inbounds.end <= output.end,
3229 "{} <= {}",
3230 output_inbounds.end,
3231 output.end
3232 );
3233
3234 let x = map_linear(value, input, 0.0..1.0);
3235 let result = if x < PCT_INBOUNDS {
3236 if output_inbounds.start == output_inbounds.end {
3237 output_inbounds.start
3238 } else {
3239 let unscaled = x * x * x * x * x * x;
3240 map_linear(unscaled, 0.0..1.0, output_inbounds)
3241 }
3242 } else {
3243 map_linear(x, 0.0..1.0, output.clone())
3244 };
3245
3246 assert!(result >= output.start, "{} >= {}", result, output.start);
3247 assert!(result <= output.end, "{} <= {}", result, output.end);
3248 result
3249 }
3250
3251 fn map_linear(
3256 value: f64,
3257 Range {
3258 start: in_low,
3259 end: in_high,
3260 }: Range<f64>,
3261 Range {
3262 start: out_low,
3263 end: out_high,
3264 }: Range<f64>,
3265 ) -> f64 {
3266 assert!(!value.is_nan(), "{}", value);
3267 assert!(value.is_finite(), "{}", value);
3268 assert!(in_low < in_high, "{in_low} < {in_high}");
3269 assert!(out_low < out_high, "{out_low} < {out_high}");
3270 assert!(value >= in_low, "{value} >= {in_low}");
3271 assert!(value <= in_high, "{value} <= {in_high}");
3272
3273 let dividend = out_high - out_low;
3274 let divisor = in_high - in_low;
3275 let slope = dividend / divisor;
3276 let result = out_low + (slope * (value - in_low));
3277
3278 assert!(result >= out_low, "{result} >= {out_low}");
3279 assert!(result <= out_high, "{result} <= {out_high}");
3280 result
3281 }
3282}
3283
3284fn arbitrary_offset(
3288 u: &mut Unstructured,
3289 limit_min: u64,
3290 limit_max: u64,
3291 segment_size: usize,
3292) -> Result<u64> {
3293 let size = u64::try_from(segment_size).unwrap();
3294
3295 if size > limit_min {
3298 u.int_in_range(0..=limit_max)
3299 } else {
3300 gradually_grow(u, 0, limit_min - size, limit_max)
3301 }
3302}
3303
3304fn unique_import_strings(max_size: usize, u: &mut Unstructured) -> Result<(String, String)> {
3305 let module = limited_string(max_size, u)?;
3306 let field = limited_string(max_size, u)?;
3307 Ok((module, field))
3308}
3309
3310fn arbitrary_vec_u8(u: &mut Unstructured) -> Result<Vec<u8>> {
3311 let size = u.arbitrary_len::<u8>()?;
3312 Ok(u.bytes(size)?.to_vec())
3313}
3314
3315impl EntityType {
3316 fn size(&self) -> u32 {
3317 match self {
3318 EntityType::Tag(_)
3319 | EntityType::Global(_)
3320 | EntityType::Table(_)
3321 | EntityType::Memory(_) => 1,
3322 EntityType::Func(_, ty) => 1 + (ty.params.len() + ty.results.len()) as u32,
3323 }
3324 }
3325}
3326
3327#[derive(Clone, Copy, Debug, Default)]
3338#[cfg_attr(
3339 feature = "serde",
3340 derive(serde_derive::Deserialize, serde_derive::Serialize)
3341)]
3342pub struct InstructionKinds(pub(crate) FlagSet<InstructionKind>);
3343
3344impl InstructionKinds {
3345 pub fn new(kinds: &[InstructionKind]) -> Self {
3347 Self(kinds.iter().fold(FlagSet::default(), |ks, k| ks | *k))
3348 }
3349
3350 pub fn all() -> Self {
3352 Self(FlagSet::full())
3353 }
3354
3355 pub fn none() -> Self {
3357 Self(FlagSet::default())
3358 }
3359
3360 #[inline]
3362 pub fn contains(&self, kind: InstructionKind) -> bool {
3363 self.0.contains(kind)
3364 }
3365
3366 pub fn without_floats(&self) -> Self {
3368 let mut floatless = self.0;
3369 if floatless.contains(InstructionKind::Numeric) {
3370 floatless -= InstructionKind::Numeric;
3371 floatless |= InstructionKind::NumericInt;
3372 }
3373 if floatless.contains(InstructionKind::Vector) {
3374 floatless -= InstructionKind::Vector;
3375 floatless |= InstructionKind::VectorInt;
3376 }
3377 if floatless.contains(InstructionKind::Memory) {
3378 floatless -= InstructionKind::Memory;
3379 floatless |= InstructionKind::MemoryInt;
3380 }
3381 Self(floatless)
3382 }
3383}
3384
3385flags! {
3386 #[allow(missing_docs)]
3389 #[cfg_attr(feature = "_internal_cli", derive(serde_derive::Deserialize))]
3390 pub enum InstructionKind: u16 {
3391 NumericInt = 1 << 0,
3392 Numeric = (1 << 1) | (1 << 0),
3393 VectorInt = 1 << 2,
3394 Vector = (1 << 3) | (1 << 2),
3395 Reference = 1 << 4,
3396 Parametric = 1 << 5,
3397 Variable = 1 << 6,
3398 Table = 1 << 7,
3399 MemoryInt = 1 << 8,
3400 Memory = (1 << 9) | (1 << 8),
3401 Control = 1 << 10,
3402 Aggregate = 1 << 11,
3403 }
3404}
3405
3406impl FromStr for InstructionKinds {
3407 type Err = String;
3408 fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
3409 let mut kinds = vec![];
3410 for part in s.split(",") {
3411 let kind = InstructionKind::from_str(part)?;
3412 kinds.push(kind);
3413 }
3414 Ok(InstructionKinds::new(&kinds))
3415 }
3416}
3417
3418impl FromStr for InstructionKind {
3419 type Err = String;
3420 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3421 match s.to_lowercase().as_str() {
3422 "numeric_non_float" => Ok(InstructionKind::NumericInt),
3423 "numeric" => Ok(InstructionKind::Numeric),
3424 "vector_non_float" => Ok(InstructionKind::VectorInt),
3425 "vector" => Ok(InstructionKind::Vector),
3426 "reference" => Ok(InstructionKind::Reference),
3427 "parametric" => Ok(InstructionKind::Parametric),
3428 "variable" => Ok(InstructionKind::Variable),
3429 "table" => Ok(InstructionKind::Table),
3430 "memory_non_float" => Ok(InstructionKind::MemoryInt),
3431 "memory" => Ok(InstructionKind::Memory),
3432 "control" => Ok(InstructionKind::Control),
3433 _ => Err(format!("unknown instruction kind: {s}")),
3434 }
3435 }
3436}
3437
3438#[cfg(feature = "wasmparser")]
3441impl TryFrom<wasmparser::FuncType> for FuncType {
3442 type Error = ();
3443
3444 fn try_from(value: wasmparser::FuncType) -> Result<Self, Self::Error> {
3445 Ok(FuncType {
3446 params: value
3447 .params()
3448 .iter()
3449 .copied()
3450 .map(|ty| ty.try_into().map_err(|_| ()))
3451 .collect::<Result<Vec<_>, _>>()?,
3452 results: value
3453 .results()
3454 .iter()
3455 .copied()
3456 .map(|ty| ty.try_into().map_err(|_| ()))
3457 .collect::<Result<Vec<_>, _>>()?,
3458 })
3459 }
3460}
3461
3462#[cfg(feature = "wasmparser")]
3463impl TryFrom<wasmparser::CompositeType> for CompositeType {
3464 type Error = ();
3465
3466 fn try_from(value: wasmparser::CompositeType) -> Result<Self, Self::Error> {
3467 let inner_type = match value.inner {
3468 wasmparser::CompositeInnerType::Func(func_type) => {
3469 CompositeInnerType::Func(Rc::new(func_type.try_into()?))
3470 }
3471 wasmparser::CompositeInnerType::Array(array_type) => {
3472 CompositeInnerType::Array(array_type.try_into().map_err(|_| ())?)
3473 }
3474 wasmparser::CompositeInnerType::Struct(struct_type) => {
3475 CompositeInnerType::Struct(struct_type.try_into().map_err(|_| ())?)
3476 }
3477 wasmparser::CompositeInnerType::Cont(_) => {
3478 panic!("continuation type is not supported by wasm-smith currently.")
3479 }
3480 };
3481
3482 Ok(CompositeType {
3483 inner: inner_type,
3484 shared: value.shared,
3485 })
3486 }
3487}
3488
3489#[cfg(feature = "wasmparser")]
3490impl TryFrom<wasmparser::SubType> for SubType {
3491 type Error = ();
3492
3493 fn try_from(value: wasmparser::SubType) -> Result<Self, Self::Error> {
3494 Ok(SubType {
3495 is_final: value.is_final,
3496 supertype: value
3497 .supertype_idx
3498 .map(|idx| idx.as_module_index().ok_or(()))
3499 .transpose()?,
3500 composite_type: value.composite_type.try_into()?,
3501 depth: 1,
3504 })
3505 }
3506}