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}