wasm_smith/
config.rs

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