Skip to content

Commit 852ee35

Browse files
authored
Protect wasm-smith against arbitrary Config differently (#1825)
* Protect wasm-smith against arbitrary `Config` differently Currently `Arbitrary for Config` will perform some internal validation of options, such as if reference-types are disabled then gc is also disabled. This validation doesn't happen for other sources of `Config` though, such as CLI options or from manual configuration. This commit moves these checks from `Arbitrary for Config` to unconditionally happening during module creation. This fixes a panic where if reference types are disabled but tables are allowed then an internal assertion was tripped because GC types were used when they shouldn't be. * Add documentation
1 parent f063a7c commit 852ee35

File tree

3 files changed

+40
-12
lines changed

3 files changed

+40
-12
lines changed

crates/wasm-smith/src/config.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -662,11 +662,7 @@ impl<'a> Arbitrary<'a> for Config {
662662
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
663663
const MAX_MAXIMUM: usize = 1000;
664664

665-
let reference_types_enabled: bool = u.arbitrary()?;
666-
let max_tables = if reference_types_enabled { 100 } else { 1 };
667-
let simd_enabled: bool = u.arbitrary()?;
668-
669-
Ok(Config {
665+
let mut config = Config {
670666
max_types: u.int_in_range(0..=MAX_MAXIMUM)?,
671667
max_imports: u.int_in_range(0..=MAX_MAXIMUM)?,
672668
max_tags: u.int_in_range(0..=MAX_MAXIMUM)?,
@@ -678,23 +674,23 @@ impl<'a> Arbitrary<'a> for Config {
678674
max_data_segments: u.int_in_range(0..=MAX_MAXIMUM)?,
679675
max_instructions: u.int_in_range(0..=MAX_MAXIMUM)?,
680676
max_memories: u.int_in_range(0..=100)?,
681-
max_tables,
677+
max_tables: u.int_in_range(0..=100)?,
682678
max_memory32_bytes: u.int_in_range(0..=u32::MAX as u64 + 1)?,
683679
max_memory64_bytes: u.int_in_range(0..=u64::MAX as u128 + 1)?,
684680
min_uleb_size: u.int_in_range(0..=5)?,
685681
bulk_memory_enabled: u.arbitrary()?,
686-
reference_types_enabled,
682+
reference_types_enabled: u.arbitrary()?,
687683
simd_enabled: u.arbitrary()?,
688684
multi_value_enabled: u.arbitrary()?,
689685
max_aliases: u.int_in_range(0..=MAX_MAXIMUM)?,
690686
max_nesting_depth: u.int_in_range(0..=10)?,
691687
saturating_float_to_int_enabled: u.arbitrary()?,
692688
sign_extension_ops_enabled: u.arbitrary()?,
693-
relaxed_simd_enabled: simd_enabled && u.arbitrary()?,
689+
relaxed_simd_enabled: u.arbitrary()?,
694690
exceptions_enabled: u.arbitrary()?,
695691
threads_enabled: u.arbitrary()?,
696692
tail_call_enabled: u.arbitrary()?,
697-
gc_enabled: reference_types_enabled && u.arbitrary()?,
693+
gc_enabled: u.arbitrary()?,
698694
allowed_instructions: {
699695
use flagset::Flags;
700696
let mut allowed = Vec::new();
@@ -742,6 +738,37 @@ impl<'a> Arbitrary<'a> for Config {
742738
// Proposals that are not stage4+ are disabled by default.
743739
memory64_enabled: false,
744740
custom_page_sizes_enabled: false,
745-
})
741+
};
742+
config.sanitize();
743+
Ok(config)
744+
}
745+
}
746+
747+
impl Config {
748+
/// "Shrink" this `Config` where appropriate to ensure its configuration is
749+
/// valid for wasm-smith.
750+
///
751+
/// This method will take the arbitrary state that this `Config` is in and
752+
/// will possibly mutate dependent options as needed by `wasm-smith`. For
753+
/// example if the `reference_types_enabled` field is turned off then
754+
/// `wasm-smith`, as of the time of this writing, additionally requires that
755+
/// the `gc_enabled` is not turned on.
756+
///
757+
/// This method will not enable anything that isn't already enabled or
758+
/// increase any limit of an item, but it may turn features off or shrink
759+
/// limits from what they're previously specified as.
760+
pub(crate) fn sanitize(&mut self) {
761+
// If reference types are disabled then automatically flag tables as
762+
// capped at 1 and disable gc as well.
763+
if !self.reference_types_enabled {
764+
self.max_tables = self.max_tables.min(1);
765+
self.gc_enabled = false;
766+
}
767+
768+
// If simd is disabled then disable all relaxed simd instructions as
769+
// well.
770+
if !self.simd_enabled {
771+
self.relaxed_simd_enabled = false;
772+
}
746773
}
747774
}

crates/wasm-smith/src/core.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ impl Module {
202202
Ok(module)
203203
}
204204

205-
fn empty(config: Config, duplicate_imports_behavior: DuplicateImportsBehavior) -> Self {
205+
fn empty(mut config: Config, duplicate_imports_behavior: DuplicateImportsBehavior) -> Self {
206+
config.sanitize();
206207
Module {
207208
config,
208209
duplicate_imports_behavior,

crates/wasm-smith/tests/core.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ fn smoke_test_reference_types() {
152152
let mut u = Unstructured::new(&buf);
153153
let mut cfg = Config::arbitrary(&mut u).unwrap();
154154
cfg.reference_types_enabled = false;
155-
cfg.max_tables = 0;
155+
cfg.max_tables = 1;
156156
if let Ok(module) = Module::new(cfg, &mut u) {
157157
let wasm_bytes = module.to_bytes();
158158
let mut features = wasm_features();

0 commit comments

Comments
 (0)