wasm_smith/
config.rs

1//! Configuring the shape of generated Wasm modules.
2
3use crate::InstructionKinds;
4use arbitrary::{Arbitrary, Result, Unstructured};
5
6macro_rules! define_config {
7    (
8        $(#[$attr:meta])*
9        pub struct Config {
10            $(
11                $(#[$field_attr:meta])*
12                pub $field:ident : $field_ty:ty = $default:expr,
13            )*
14        }
15    ) => {
16        $(#[$attr])*
17        pub struct Config {
18            /// The imports that may be used when generating the module.
19            ///
20            /// Defaults to `None` which means that any arbitrary import can be
21            /// generated.
22            ///
23            /// To only allow specific imports, set this field to a WebAssembly
24            /// module which describes the imports allowed.
25            ///
26            /// Note that [`Self::min_imports`] is ignored when
27            /// `available_imports` are enabled.
28            ///
29            /// The provided value must be a valid binary encoding of a
30            /// WebAssembly module. `wasm-smith` will panic if the module cannot
31            /// be parsed.
32            ///
33            /// # Example
34            ///
35            /// An implementation of this method could use the `wat` crate to
36            /// provide a human-readable and maintainable description:
37            ///
38            /// ```rust
39            /// Some(wat::parse_str(r#"
40            ///     (module
41            ///         (import "env" "ping" (func (param i32)))
42            ///         (import "env" "pong" (func (result i32)))
43            ///         (import "env" "memory" (memory 1))
44            ///         (import "env" "table" (table 1))
45            ///         (import "env" "tag" (tag (param i32)))
46            ///     )
47            /// "#))
48            /// # ;
49            /// ```
50            pub available_imports: Option<Vec<u8>>,
51
52            /// If provided, the generated module will have exports with exactly
53            /// the same names and types as those in the provided WebAssembly
54            /// module. The implementation (e.g. function bodies, global
55            /// initializers) of each export in the generated module will be
56            /// random and unrelated to the implementation in the provided
57            /// module. Only globals and functions are supported.
58            ///
59            ///
60            /// Defaults to `None` which means arbitrary exports will be
61            /// generated.
62            ///
63            /// To specify which exports the generated modules should have, set
64            /// this field to a WebAssembly module which describes the desired
65            /// exports. To generate modules with varying exports that meet some
66            /// constraints, consider randomly generating the value for this
67            /// field.
68            ///
69            /// The provided value must be a valid binary encoding of a
70            /// WebAssembly module. `wasm-smith` will panic if the module cannot
71            /// be parsed.
72            ///
73            /// # Module Limits
74            ///
75            /// All types, functions, globals, and exports that are needed to
76            /// provide the required exports will be generated, even if it
77            /// causes the resulting module to exceed the limits defined in
78            /// [`Self::max_type_size`], [`Self::max_types`],
79            /// [`Self::max_funcs`], [`Self::max_globals`], or
80            /// [`Self::max_exports`].
81            ///
82            /// # Example
83            ///
84            /// As for [`Self::available_imports`], the `wat` crate can be used
85            /// to provide an human-readable description of the desired exports:
86            ///
87            /// ```rust
88            /// Some(wat::parse_str(r#"
89            ///     (module
90            ///         (func (export "foo") (param i32) (result i64) unreachable)
91            ///         (global (export "bar") f32 f32.const 0)
92            ///     )
93            /// "#));
94            /// ```
95            pub exports: Option<Vec<u8>>,
96
97            $(
98                $(#[$field_attr])*
99                pub $field: $field_ty,
100            )*
101        }
102
103        impl Default for Config {
104            fn default() -> Config {
105                Config {
106                    available_imports: None,
107                    exports: None,
108
109                    $(
110                        $field: $default,
111                    )*
112                }
113            }
114        }
115
116        #[cfg(feature = "_internal_cli")]
117        #[doc(hidden)]
118        #[derive(Clone, Debug, Default, clap::Parser, serde_derive::Deserialize)]
119        #[serde(rename_all = "kebab-case", deny_unknown_fields)]
120        pub struct InternalOptionalConfig {
121            /// The imports that may be used when generating the module.
122            ///
123            /// When unspecified, any arbitrary import can be generated.
124            ///
125            /// To only allow specific imports, provide a file path of a
126            /// WebAssembly module which describes the imports allowed.
127            ///
128            /// Note that [`Self::min_imports`] is ignored when
129            /// `available_imports` are enabled.
130            ///
131            /// The provided value must be a valid binary encoding of a
132            /// WebAssembly module. `wasm-smith` will panic if the module cannot
133            /// be parsed.
134            #[cfg_attr(feature = "clap", clap(long))]
135            available_imports: Option<std::path::PathBuf>,
136
137            /// If provided, the generated module will have exports with exactly
138            /// the same names and types as those in the provided WebAssembly
139            /// module. The implementation (e.g. function bodies, global
140            /// initializers) of each export in the generated module will be
141            /// random and unrelated to the implementation in the provided
142            /// module. Only globals and functions are supported.
143            ///
144            /// Defaults to `None` which means arbitrary exports will be
145            /// generated.
146            ///
147            /// To specify which exports the generated modules should have, set
148            /// this field to a WebAssembly module which describes the desired
149            /// exports. To generate modules with varying exports that meet some
150            /// constraints, consider randomly generating the value for this
151            /// field.
152            ///
153            /// The provided value must be a valid binary encoding of a
154            /// WebAssembly module. `wasm-smith` will panic if the module cannot
155            /// be parsed.
156            ///
157            /// # Module Limits
158            ///
159            /// All types, functions, globals, and exports that are needed to
160            /// provide the required exports will be generated, even if it
161            /// causes the resulting module to exceed the limits defined in
162            /// [`Self::max_type_size`], [`Self::max_types`],
163            /// [`Self::max_funcs`], [`Self::max_globals`], or
164            /// [`Self::max_exports`].
165            ///
166            #[cfg_attr(feature = "clap", clap(long))]
167            exports: Option<std::path::PathBuf>,
168
169            $(
170                $(#[$field_attr])*
171                #[cfg_attr(feature = "clap", clap(long))]
172                pub $field: Option<$field_ty>,
173            )*
174        }
175
176        #[cfg(feature = "_internal_cli")]
177        impl InternalOptionalConfig {
178            pub fn or(self, other: Self) -> Self {
179                Self {
180                    available_imports: self.available_imports.or(other.available_imports),
181                    exports: self.exports.or(other.exports),
182
183                    $(
184                        $field: self.$field.or(other.$field),
185                    )*
186                }
187            }
188        }
189
190        #[cfg(feature = "_internal_cli")]
191        impl TryFrom<InternalOptionalConfig> for Config {
192            type Error = anyhow::Error;
193            fn try_from(config: InternalOptionalConfig) -> anyhow::Result<Config> {
194                let default = Config::default();
195                Ok(Config {
196                    available_imports: if let Some(file) = config
197                        .available_imports
198                        .as_ref() {
199                            Some(wat::parse_file(file)?)
200                        } else {
201                            None
202                        },
203                    exports: if let Some(file) = config
204                        .exports
205                        .as_ref() {
206                            Some(wat::parse_file(file)?)
207                        } else {
208                            None
209                        },
210
211                    $(
212                        $field: config.$field.unwrap_or(default.$field),
213                    )*
214                })
215            }
216        }
217    }
218}
219
220define_config! {
221    /// Configuration for a generated module.
222    ///
223    /// Don't care to configure your generated modules? Just use
224    /// [`Module::arbitrary`][crate::Module], which internally uses the default
225    /// configuration.
226    ///
227    /// Want control over the shape of the module that gets generated? Create a
228    /// `Config` and then pass it to [`Module::new`][crate::Module::new].
229    ///
230    /// # Swarm Testing
231    ///
232    /// You can use the `Arbitrary for Config` implementation for [swarm
233    /// testing]. This will dynamically -- but still deterministically -- choose
234    /// configuration options for you.
235    ///
236    /// [swarm testing]: https://www.cs.utah.edu/~regehr/papers/swarm12.pdf
237    ///
238    /// Note that we pick only *maximums*, not minimums, here because it is more
239    /// complex to describe the domain of valid configs when minima are involved
240    /// (`min <= max` for each variable) and minima are mostly used to ensure
241    /// certain elements are present, but do not widen the range of generated
242    /// Wasm modules.
243    #[derive(Clone, Debug)]
244    pub struct Config {
245        /// Determines whether a `start` export may be included. Defaults to `true`.
246        pub allow_start_export: bool = true,
247
248        /// The kinds of instructions allowed in the generated wasm
249        /// programs. Defaults to all.
250        ///
251        /// The categories of instructions match the categories used by the
252        /// [WebAssembly
253        /// specification](https://webassembly.github.io/spec/core/syntax/instructions.html);
254        /// e.g., numeric, vector, control, memory, etc.
255        ///
256        /// Additionally, we include finer-grained categories which exclude floating point
257        /// instructions, e.g. [`InstructionKind::NumericInt`] is a subset of
258        /// [`InstructionKind::Numeric`] consisting of all numeric instructions which
259        /// don't involve floats.
260        ///
261        /// Note that modifying this setting is separate from the proposal
262        /// flags; that is, if `simd_enabled() == true` but
263        /// `allowed_instruction()` does not include vector instructions, the
264        /// generated programs will not include these instructions but could
265        /// contain vector types.
266        ///
267        /// [`InstructionKind::Numeric`]: crate::InstructionKind::Numeric
268        /// [`InstructionKind::NumericInt`]: crate::InstructionKind::NumericInt
269        pub allowed_instructions: InstructionKinds = InstructionKinds::all(),
270
271        /// Determines whether we generate floating point instructions and types.
272        ///
273        /// Defaults to `true`.
274        pub allow_floats: bool = true,
275
276        /// Determines whether the bulk memory proposal is enabled for
277        /// generating instructions.
278        ///
279        /// Defaults to `true`.
280        pub bulk_memory_enabled: bool = true,
281
282        /// Returns whether NaN values are canonicalized after all f32/f64
283        /// operation. Defaults to false.
284        ///
285        /// This can be useful when a generated wasm module is executed in
286        /// multiple runtimes which may produce different NaN values. This
287        /// ensures that the generated module will always use the same NaN
288        /// representation for all instructions which have visible side effects,
289        /// for example writing floats to memory or float-to-int bitcast
290        /// instructions.
291        pub canonicalize_nans: bool = false,
292
293        /// Returns whether we should avoid generating code that will possibly
294        /// trap.
295        ///
296        /// For some trapping instructions, this will emit extra instructions to
297        /// ensure they don't trap, while some instructions will simply be
298        /// excluded.  In cases where we would run into a trap, we instead
299        /// choose some arbitrary non-trapping behavior. For example, if we
300        /// detect that a Load instruction would attempt to access out-of-bounds
301        /// memory, we instead pretend the load succeeded and push 0 onto the
302        /// stack.
303        ///
304        /// One type of trap that we can't currently avoid is
305        /// StackOverflow. Even when `disallow_traps` is set to true, wasm-smith
306        /// will eventually generate a program that infinitely recurses, causing
307        /// the call stack to be exhausted.
308        ///
309        /// Defaults to `false`.
310        pub disallow_traps: bool = false,
311
312        /// Determines whether the exception-handling proposal is enabled for
313        /// generating instructions.
314        ///
315        /// Defaults to `true`.
316        pub exceptions_enabled: bool = true,
317
318        /// Export all WebAssembly objects in the module. Defaults to false.
319        ///
320        /// This overrides [`Config::min_exports`] and [`Config::max_exports`].
321        pub export_everything: bool = false,
322
323        /// Determines whether the GC proposal is enabled when generating a Wasm
324        /// module.
325        ///
326        /// Defaults to `true`.
327        pub gc_enabled: bool = true,
328
329        /// Determines whether the custom-page-sizes proposal is enabled when
330        /// generating a Wasm module.
331        ///
332        /// Defaults to `false`.
333        pub custom_page_sizes_enabled: bool = false,
334
335        /// Returns whether we should generate custom sections or not. Defaults
336        /// to false.
337        pub generate_custom_sections: bool = false,
338
339        /// Returns the maximal size of the `alias` section. Defaults to 1000.
340        pub max_aliases: usize = 1000,
341
342        /// The maximum number of components to use. Defaults to 10.
343        ///
344        /// This includes imported components.
345        ///
346        /// Note that this is only relevant for components.
347        pub max_components: usize = 10,
348
349        /// The maximum number of data segments to generate. Defaults to 100.
350        pub max_data_segments: usize = 100,
351
352        /// The maximum number of element segments to generate. Defaults to 100.
353        pub max_element_segments: usize = 100,
354
355        /// The maximum number of elements within a segment to
356        /// generate. Defaults to 100.
357        pub max_elements: usize = 100,
358
359        /// The maximum number of exports to generate. Defaults to 100.
360        pub max_exports: usize = 100,
361
362        /// The maximum number of functions to generate. Defaults to 100.  This
363        /// includes imported functions.
364        pub max_funcs: usize = 100,
365
366        /// The maximum number of globals to generate. Defaults to 100.  This
367        /// includes imported globals.
368        pub max_globals: usize = 100,
369
370        /// The maximum number of imports to generate. Defaults to 100.
371        pub max_imports: usize = 100,
372
373        /// The maximum number of instances to use. Defaults to 10.
374        ///
375        /// This includes imported instances.
376        ///
377        /// Note that this is only relevant for components.
378        pub max_instances: usize = 10,
379
380        /// The maximum number of instructions to generate in a function
381        /// body. Defaults to 100.
382        ///
383        /// Note that some additional `end`s, `else`s, and `unreachable`s may be
384        /// appended to the function body to finish block scopes.
385        pub max_instructions: usize = 100,
386
387        /// The maximum number of memories to use. Defaults to 1.
388        ///
389        /// This includes imported memories.
390        ///
391        /// Note that more than one memory is in the realm of the multi-memory
392        /// wasm proposal.
393        pub max_memories: usize = 1,
394
395        /// The maximum, in bytes, of any 32-bit memory's initial or maximum
396        /// size.
397        ///
398        /// May not be larger than `2**32`.
399        ///
400        /// Defaults to `2**32`.
401        pub max_memory32_bytes: u64 = u32::MAX as u64 + 1,
402
403        /// The maximum, in bytes, of any 64-bit memory's initial or maximum
404        /// size.
405        ///
406        /// May not be larger than `2**64`.
407        ///
408        /// Defaults to `2**64`.
409        pub max_memory64_bytes: u128 = u64::MAX as u128 + 1,
410
411        /// The maximum number of modules to use. Defaults to 10.
412        ///
413        /// This includes imported modules.
414        ///
415        /// Note that this is only relevant for components.
416        pub max_modules: usize = 10,
417
418        /// Returns the maximal nesting depth of modules with the component
419        /// model proposal. Defaults to 10.
420        pub max_nesting_depth: usize = 10,
421
422        /// The maximum, elements, of any table's initial or maximum
423        /// size. Defaults to 1 million.
424        pub max_table_elements: u64 = 1_000_000,
425
426        /// The maximum number of tables to use. Defaults to 1.
427        ///
428        /// This includes imported tables.
429        ///
430        /// Note that more than one table is in the realm of the reference types
431        /// proposal.
432        pub max_tables: usize = 1,
433
434        /// The maximum number of tags to generate. Defaults to 100.
435        pub max_tags: usize = 100,
436
437        /// Returns the maximal effective size of any type generated by
438        /// wasm-smith.
439        ///
440        /// Note that this number is roughly in units of "how many types would
441        /// be needed to represent the recursive type". A function with 8
442        /// parameters and 2 results would take 11 types (one for the type, 10
443        /// for params/results). A module type with 2 imports and 3 exports
444        /// would take 6 (module + imports + exports) plus the size of each
445        /// import/export type. This is a somewhat rough measurement that is not
446        /// intended to be very precise.
447        ///
448        /// Defaults to 1000.
449        pub max_type_size: u32 = 1000,
450
451        /// The maximum number of types to generate. Defaults to 100.
452        pub max_types: usize = 100,
453
454        /// The maximum number of values to use. Defaults to 10.
455        ///
456        /// This includes imported values.
457        ///
458        /// Note that this is irrelevant unless value model support is enabled.
459        pub max_values: usize = 10,
460
461        /// Returns whether 64-bit memories are allowed. Defaults to true.
462        ///
463        /// Note that this is the gate for the memory64 proposal to WebAssembly.
464        pub memory64_enabled: bool = true,
465
466        /// Whether every Wasm memory must have a maximum size
467        /// specified. Defaults to `false`.
468        pub memory_max_size_required: bool = false,
469
470        /// Control the probability of generating memory offsets that are in
471        /// bounds vs. potentially out of bounds.
472        ///
473        /// See the `MemoryOffsetChoices` struct for details.
474        pub memory_offset_choices: MemoryOffsetChoices = MemoryOffsetChoices::default(),
475
476        /// The minimum number of data segments to generate. Defaults to 0.
477        pub min_data_segments: usize = 0,
478
479        /// The minimum number of element segments to generate. Defaults to 0.
480        pub min_element_segments: usize = 0,
481
482        /// The minimum number of elements within a segment to
483        /// generate. Defaults to 0.
484        pub min_elements: usize = 0,
485
486        /// The minimum number of exports to generate. Defaults to 0.
487        pub min_exports: usize = 0,
488
489        /// The minimum number of functions to generate. Defaults to 0.
490        ///
491        /// This includes imported functions.
492        pub min_funcs: usize = 0,
493
494        /// The minimum number of globals to generate. Defaults to 0.
495        ///
496        /// This includes imported globals.
497        pub min_globals: usize = 0,
498
499        /// The minimum number of imports to generate. Defaults to 0.
500        ///
501        /// Note that if the sum of the maximum function[^1], table, global and
502        /// memory counts is less than the minimum number of imports, then it
503        /// will not be possible to satisfy all constraints (because imports
504        /// count against the limits for those element kinds). In that case, we
505        /// strictly follow the max-constraints, and can fail to satisfy this
506        /// minimum number.
507        ///
508        /// [^1]: the maximum number of functions is also limited by the number
509        /// of function types arbitrarily chosen; strictly speaking, then, the
510        /// maximum number of imports that can be created due to max-constraints
511        /// is `sum(min(num_func_types, max_funcs), max_tables, max_globals,
512        /// max_memories)`.
513        pub min_imports: usize = 0,
514
515        /// The minimum number of memories to use. Defaults to 0.
516        ///
517        /// This includes imported memories.
518        pub min_memories: u32 = 0,
519
520        /// The minimum number of tables to use. Defaults to 0.
521        ///
522        /// This includes imported tables.
523        pub min_tables: u32 = 0,
524
525        /// The minimum number of tags to generate. Defaults to 0.
526        pub min_tags: usize = 0,
527
528        /// The minimum number of types to generate. Defaults to 0.
529        pub min_types: usize = 0,
530
531        /// The minimum size, in bytes, of all leb-encoded integers. Defaults to
532        /// 1.
533        ///
534        /// This is useful for ensuring that all leb-encoded integers are
535        /// decoded as such rather than as simply one byte. This will forcibly
536        /// extend leb integers with an over-long encoding in some locations if
537        /// the size would otherwise be smaller than number returned here.
538        pub min_uleb_size: u8 = 1,
539
540        /// Determines whether the multi-value results are enabled.
541        ///
542        /// Defaults to `true`.
543        pub multi_value_enabled: bool = true,
544
545        /// Determines whether the reference types proposal is enabled for
546        /// generating instructions.
547        ///
548        /// Defaults to `true`.
549        pub reference_types_enabled: bool = true,
550
551        /// Determines whether the Relaxed SIMD proposal is enabled for
552        /// generating instructions.
553        ///
554        /// Defaults to `true`.
555        pub relaxed_simd_enabled: bool = true,
556
557        /// Determines whether the non-trapping float-to-int conversions
558        /// proposal is enabled.
559        ///
560        /// Defaults to `true`.
561        pub saturating_float_to_int_enabled: bool = true,
562
563        /// Determines whether the sign-extension-ops proposal is enabled.
564        ///
565        /// Defaults to `true`.
566        pub sign_extension_ops_enabled: bool = true,
567
568        /// Determines whether the shared-everything-threads proposal is
569        /// enabled.
570        ///
571        /// The [shared-everything-threads] proposal, among other things,
572        /// extends `shared` attributes to all WebAssembly objects; it builds on
573        /// the [threads] proposal.
574        ///
575        /// [shared-everything-threads]: https://github.com/WebAssembly/shared-everything-threads
576        /// [threads]: https://github.com/WebAssembly/threads
577        ///
578        /// Defaults to `false`.
579        pub shared_everything_threads_enabled: bool = false,
580
581        /// Determines whether the SIMD proposal is enabled for generating
582        /// instructions.
583        ///
584        /// Defaults to `true`.
585        pub simd_enabled: bool = true,
586
587        /// Determines whether the tail calls proposal is enabled for generating
588        /// instructions.
589        ///
590        /// Defaults to `true`.
591        pub tail_call_enabled: bool = true,
592
593        /// Whether every Wasm table must have a maximum size
594        /// specified. Defaults to `false`.
595        pub table_max_size_required: bool = false,
596
597        /// Determines whether the threads proposal is enabled.
598        ///
599        /// The [threads proposal] involves shared linear memory, new atomic
600        /// instructions, and new `wait` and `notify` instructions.
601        ///
602        /// [threads proposal]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
603        ///
604        /// Defaults to `true`.
605        pub threads_enabled: bool = true,
606
607        /// Indicates whether wasm-smith is allowed to generate invalid function
608        /// bodies.
609        ///
610        /// When enabled this option will enable taking raw bytes from the input
611        /// byte stream and using them as a wasm function body. This means that
612        /// the output module is not guaranteed to be valid but can help tickle
613        /// various parts of validation/compilation in some circumstances as
614        /// well.
615        ///
616        /// Defaults to `false`.
617        pub allow_invalid_funcs: bool = false,
618
619        /// Determines whether the [wide-arithmetic proposal] is enabled.
620        ///
621        /// [wide-arithmetic proposal]: https://github.com/WebAssembly/wide-arithmetic
622        ///
623        /// Defaults to `false`.
624        pub wide_arithmetic_enabled: bool = false,
625
626        /// Determines whether the [extended-const proposal] is enabled.
627        ///
628        /// [extended-const proposal]: https://github.com/WebAssembly/extended-const
629        ///
630        /// Defaults to `true`.
631        pub extended_const_enabled: bool = true,
632    }
633}
634
635/// This is a tuple `(a, b, c)` where
636///
637/// * `a / (a+b+c)` is the probability of generating a memory offset within
638///   `0..memory.min_size`, i.e. an offset that is definitely in bounds of a
639///   non-empty memory. (Note that if a memory is zero-sized, however, no offset
640///   will ever be in bounds.)
641///
642/// * `b / (a+b+c)` is the probability of generating a memory offset within
643///   `memory.min_size..memory.max_size`, i.e. an offset that is possibly in
644///   bounds if the memory has been grown.
645///
646/// * `c / (a+b+c)` is the probability of generating a memory offset within the
647///   range `memory.max_size..`, i.e. an offset that is definitely out of
648///   bounds.
649///
650/// At least one of `a`, `b`, and `c` must be non-zero.
651///
652/// If you want to always generate memory offsets that are definitely in bounds
653/// of a non-zero-sized memory, for example, you could return `(1, 0, 0)`.
654///
655/// The default is `(90, 9, 1)`.
656#[derive(Clone, Debug)]
657#[cfg_attr(feature = "serde_derive", derive(serde_derive::Deserialize))]
658pub struct MemoryOffsetChoices(pub u32, pub u32, pub u32);
659
660impl Default for MemoryOffsetChoices {
661    fn default() -> Self {
662        MemoryOffsetChoices(90, 9, 1)
663    }
664}
665
666#[cfg(feature = "_internal_cli")]
667impl std::str::FromStr for MemoryOffsetChoices {
668    type Err = String;
669    fn from_str(s: &str) -> Result<Self, Self::Err> {
670        use std::str::FromStr;
671        let mut parts = s.split(",");
672        let a = parts
673            .next()
674            .ok_or_else(|| "need 3 comma separated values".to_string())?;
675        let a = <u32 as FromStr>::from_str(a).map_err(|e| e.to_string())?;
676        let b = parts
677            .next()
678            .ok_or_else(|| "need 3 comma separated values".to_string())?;
679        let b = <u32 as FromStr>::from_str(b).map_err(|e| e.to_string())?;
680        let c = parts
681            .next()
682            .ok_or_else(|| "need 3 comma separated values".to_string())?;
683        let c = <u32 as FromStr>::from_str(c).map_err(|e| e.to_string())?;
684        if parts.next().is_some() {
685            return Err("found more than 3 comma separated values".to_string());
686        }
687        Ok(MemoryOffsetChoices(a, b, c))
688    }
689}
690
691impl<'a> Arbitrary<'a> for Config {
692    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
693        const MAX_MAXIMUM: usize = 1000;
694
695        let mut config = Config {
696            max_types: u.int_in_range(0..=MAX_MAXIMUM)?,
697            max_imports: u.int_in_range(0..=MAX_MAXIMUM)?,
698            max_tags: u.int_in_range(0..=MAX_MAXIMUM)?,
699            max_funcs: u.int_in_range(0..=MAX_MAXIMUM)?,
700            max_globals: u.int_in_range(0..=MAX_MAXIMUM)?,
701            max_exports: u.int_in_range(0..=MAX_MAXIMUM)?,
702            max_element_segments: u.int_in_range(0..=MAX_MAXIMUM)?,
703            max_elements: u.int_in_range(0..=MAX_MAXIMUM)?,
704            max_data_segments: u.int_in_range(0..=MAX_MAXIMUM)?,
705            max_instructions: u.int_in_range(0..=MAX_MAXIMUM)?,
706            max_memories: u.int_in_range(0..=100)?,
707            max_tables: u.int_in_range(0..=100)?,
708            max_memory32_bytes: u.int_in_range(0..=u32::MAX as u64 + 1)?,
709            max_memory64_bytes: u.int_in_range(0..=u64::MAX as u128 + 1)?,
710            min_uleb_size: u.int_in_range(0..=5)?,
711            bulk_memory_enabled: u.arbitrary()?,
712            reference_types_enabled: u.arbitrary()?,
713            simd_enabled: u.arbitrary()?,
714            multi_value_enabled: u.arbitrary()?,
715            max_aliases: u.int_in_range(0..=MAX_MAXIMUM)?,
716            max_nesting_depth: u.int_in_range(0..=10)?,
717            saturating_float_to_int_enabled: u.arbitrary()?,
718            sign_extension_ops_enabled: u.arbitrary()?,
719            relaxed_simd_enabled: u.arbitrary()?,
720            exceptions_enabled: u.arbitrary()?,
721            threads_enabled: u.arbitrary()?,
722            tail_call_enabled: u.arbitrary()?,
723            gc_enabled: u.arbitrary()?,
724            memory64_enabled: u.arbitrary()?,
725            allowed_instructions: {
726                use flagset::Flags;
727                let mut allowed = Vec::new();
728                for kind in crate::core::InstructionKind::LIST {
729                    if u.arbitrary()? {
730                        allowed.push(*kind);
731                    }
732                }
733                InstructionKinds::new(&allowed)
734            },
735            table_max_size_required: u.arbitrary()?,
736            max_table_elements: u.int_in_range(0..=1_000_000)?,
737            disallow_traps: u.arbitrary()?,
738            allow_floats: u.arbitrary()?,
739            extended_const_enabled: u.arbitrary()?,
740
741            // These fields, unlike the ones above, are less useful to set.
742            // They either make weird inputs or are for features not widely
743            // implemented yet so they're turned off by default.
744            min_types: 0,
745            min_imports: 0,
746            min_tags: 0,
747            min_funcs: 0,
748            min_globals: 0,
749            min_exports: 0,
750            min_element_segments: 0,
751            min_elements: 0,
752            min_data_segments: 0,
753            min_memories: 0,
754            min_tables: 0,
755            memory_max_size_required: false,
756            max_instances: 0,
757            max_modules: 0,
758            max_components: 0,
759            max_values: 0,
760            memory_offset_choices: MemoryOffsetChoices::default(),
761            allow_start_export: true,
762            max_type_size: 1000,
763            canonicalize_nans: false,
764            available_imports: None,
765            exports: None,
766            export_everything: false,
767            generate_custom_sections: false,
768            allow_invalid_funcs: false,
769
770            // Proposals that are not stage4+ are disabled by default.
771            custom_page_sizes_enabled: false,
772            wide_arithmetic_enabled: false,
773            shared_everything_threads_enabled: false,
774        };
775        config.sanitize();
776        Ok(config)
777    }
778}
779
780impl Config {
781    /// "Shrink" this `Config` where appropriate to ensure its configuration is
782    /// valid for wasm-smith.
783    ///
784    /// This method will take the arbitrary state that this `Config` is in and
785    /// will possibly mutate dependent options as needed by `wasm-smith`. For
786    /// example if the `reference_types_enabled` field is turned off then
787    /// `wasm-smith`, as of the time of this writing, additionally requires that
788    /// the `gc_enabled` is not turned on.
789    ///
790    /// This method will not enable anything that isn't already enabled or
791    /// increase any limit of an item, but it may turn features off or shrink
792    /// limits from what they're previously specified as.
793    pub(crate) fn sanitize(&mut self) {
794        // If reference types are disabled then automatically flag tables as
795        // capped at 1 and disable gc as well.
796        if !self.reference_types_enabled {
797            self.max_tables = self.max_tables.min(1);
798            self.gc_enabled = false;
799            self.shared_everything_threads_enabled = false;
800        }
801
802        // shared-everything-threads depends on GC, so if gc is disabled then
803        // also disable shared-everything-threads.
804        if !self.gc_enabled {
805            self.shared_everything_threads_enabled = false;
806        }
807
808        // If simd is disabled then disable all relaxed simd instructions as
809        // well.
810        if !self.simd_enabled {
811            self.relaxed_simd_enabled = false;
812        }
813
814        // It is impossible to use the shared-everything-threads proposal
815        // without threads, which it is built on.
816        if !self.threads_enabled {
817            self.shared_everything_threads_enabled = false;
818        }
819    }
820
821    /// Returns the set of features that are necessary for validating against
822    /// this `Config`.
823    #[cfg(feature = "wasmparser")]
824    pub fn features(&self) -> wasmparser::WasmFeatures {
825        use wasmparser::WasmFeatures;
826
827        // Currently wasm-smith doesn't have knobs for the MVP (floats) or
828        // `mutable-global`. These are unconditionally enabled.
829        let mut features = WasmFeatures::MUTABLE_GLOBAL | WasmFeatures::WASM1;
830
831        // All other features that can be generated by wasm-smith are gated by
832        // configuration fields. Conditionally set each feature based on the
833        // status of the fields in `self`.
834        features.set(
835            WasmFeatures::SATURATING_FLOAT_TO_INT,
836            self.saturating_float_to_int_enabled,
837        );
838        features.set(
839            WasmFeatures::SIGN_EXTENSION,
840            self.sign_extension_ops_enabled,
841        );
842        features.set(WasmFeatures::REFERENCE_TYPES, self.reference_types_enabled);
843        features.set(WasmFeatures::MULTI_VALUE, self.multi_value_enabled);
844        features.set(WasmFeatures::BULK_MEMORY, self.bulk_memory_enabled);
845        features.set(WasmFeatures::SIMD, self.simd_enabled);
846        features.set(WasmFeatures::RELAXED_SIMD, self.relaxed_simd_enabled);
847        features.set(WasmFeatures::MULTI_MEMORY, self.max_memories > 1);
848        features.set(WasmFeatures::EXCEPTIONS, self.exceptions_enabled);
849        features.set(WasmFeatures::MEMORY64, self.memory64_enabled);
850        features.set(WasmFeatures::TAIL_CALL, self.tail_call_enabled);
851        features.set(WasmFeatures::FUNCTION_REFERENCES, self.gc_enabled);
852        features.set(WasmFeatures::GC, self.gc_enabled);
853        features.set(WasmFeatures::THREADS, self.threads_enabled);
854        features.set(
855            WasmFeatures::SHARED_EVERYTHING_THREADS,
856            self.shared_everything_threads_enabled,
857        );
858        features.set(
859            WasmFeatures::CUSTOM_PAGE_SIZES,
860            self.custom_page_sizes_enabled,
861        );
862        features.set(WasmFeatures::EXTENDED_CONST, self.extended_const_enabled);
863        features.set(WasmFeatures::WIDE_ARITHMETIC, self.wide_arithmetic_enabled);
864
865        features
866    }
867}