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