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