Skip to content

Commit c59fb63

Browse files
authored
wasm-smith: Allow limiting the size of const arrays (bytecodealliance#2536)
* wasm-smith: Allow limiting the size of const arrays This adds some config knobs to `wasm-smith` to enable limiting the dynamic size of constant expressions in generated modules, notably the array lengths. This additionally tweaks the fuel consumption strategy and moves the compile-time constant to a runtime constant. cc bytecodealliance/wasmtime#13521 * Fix msrv
1 parent 74145d2 commit c59fb63

2 files changed

Lines changed: 49 additions & 32 deletions

File tree

crates/wasm-smith/src/config.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,17 @@ define_config! {
737737
///
738738
/// Defaults to `true`.
739739
pub extended_const_enabled: bool = true,
740+
741+
/// Fuel limiting factor used when generating constant expressions.
742+
///
743+
/// Defaults to `50`.
744+
pub const_expr_fuel: u32 = 50,
745+
746+
/// Whether or not to limit the size of arrays generated in constant
747+
/// expressions.
748+
///
749+
/// Defaults to `false`.
750+
pub limit_arrays_in_const_exprs: bool = false,
740751
}
741752
}
742753

@@ -847,6 +858,8 @@ impl<'a> Arbitrary<'a> for Config {
847858
disallow_traps: u.arbitrary()?,
848859
allow_floats: u.arbitrary()?,
849860
extended_const_enabled: u.arbitrary()?,
861+
const_expr_fuel: u.int_in_range(0..=100)?,
862+
limit_arrays_in_const_exprs: u.arbitrary()?,
850863

851864
// These fields, unlike the ones above, are less useful to set.
852865
// They either make weird inputs or are for features not widely

crates/wasm-smith/src/core.rs

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,8 +2044,6 @@ impl Module {
20442044
u: &mut Unstructured,
20452045
allow_defined_globals: bool,
20462046
) -> Result<ConstExpr> {
2047-
const MAX_CONST_EXPR_RECURSION_DEPTH: usize = 8;
2048-
20492047
#[derive(Clone, Copy)]
20502048
enum Choice {
20512049
GlobalGet(u32),
@@ -2163,12 +2161,27 @@ impl Module {
21632161
.all(|f| type_is_defaultable(f.element_type))
21642162
}
21652163

2164+
fn const_expr_bytes_for_array_length(
2165+
module: &mut Module,
2166+
u: &mut Unstructured<'_>,
2167+
allow_defined_globals: bool,
2168+
fuel: &mut u32,
2169+
) -> Result<Vec<u8>> {
2170+
if module.config.limit_arrays_in_const_exprs {
2171+
let size = u.int_in_range(0..=*fuel)?;
2172+
*fuel -= size;
2173+
return Ok(encode_instrs([Instruction::I32Const(size as i32)]));
2174+
}
2175+
2176+
const_expr_bytes(module, ValType::I32, u, allow_defined_globals, fuel)
2177+
}
2178+
21662179
fn const_expr_bytes(
21672180
module: &mut Module,
21682181
ty: ValType,
21692182
u: &mut Unstructured<'_>,
21702183
allow_defined_globals: bool,
2171-
fuel: usize,
2184+
fuel: &mut u32,
21722185
) -> Result<Vec<u8>> {
21732186
let mut choices = Vec::new();
21742187

@@ -2215,7 +2228,7 @@ impl Module {
22152228
continue;
22162229
}
22172230
if can_use_struct_new(module.ty(type_idx))
2218-
&& (fuel > 0
2231+
&& (*fuel > 0
22192232
|| module.ty(type_idx).unwrap_struct().fields.is_empty())
22202233
{
22212234
choices.push(Choice::StructNew(type_idx));
@@ -2230,7 +2243,7 @@ impl Module {
22302243
if !module.ref_type_is_sub_type(produced, ref_ty) {
22312244
continue;
22322245
}
2233-
if fuel > 0 {
2246+
if *fuel > 0 {
22342247
choices.push(Choice::ArrayNew(type_idx));
22352248
choices.push(Choice::ArrayNewFixed(type_idx));
22362249
if type_is_defaultable(
@@ -2242,13 +2255,13 @@ impl Module {
22422255
}
22432256

22442257
let produced_i31 = abstract_ref(false, false, AbstractHeapType::I31);
2245-
if fuel > 0 && module.ref_type_is_sub_type(produced_i31, ref_ty) {
2258+
if *fuel > 0 && module.ref_type_is_sub_type(produced_i31, ref_ty) {
22462259
choices.push(Choice::RefI31 { shared: false });
22472260
}
22482261

22492262
if module.config.shared_everything_threads_enabled {
22502263
let produced_i31 = abstract_ref(false, true, AbstractHeapType::I31);
2251-
if fuel > 0 && module.ref_type_is_sub_type(produced_i31, ref_ty) {
2264+
if *fuel > 0 && module.ref_type_is_sub_type(produced_i31, ref_ty) {
22522265
choices.push(Choice::RefI31 { shared: true });
22532266
}
22542267
}
@@ -2257,7 +2270,7 @@ impl Module {
22572270
HeapType::Abstract {
22582271
shared,
22592272
ty: AbstractHeapType::Any,
2260-
} if fuel > 0 => {
2273+
} if *fuel > 0 => {
22612274
choices.push(Choice::AnyConvertExtern {
22622275
nullable: ref_ty.nullable,
22632276
shared,
@@ -2266,7 +2279,7 @@ impl Module {
22662279
HeapType::Abstract {
22672280
shared,
22682281
ty: AbstractHeapType::Extern,
2269-
} if fuel > 0 => {
2282+
} if *fuel > 0 => {
22702283
choices.push(Choice::ExternConvertAny {
22712284
nullable: ref_ty.nullable,
22722285
shared,
@@ -2279,6 +2292,7 @@ impl Module {
22792292
}
22802293

22812294
let choice = *u.choose(&choices)?;
2295+
*fuel = fuel.saturating_sub(1);
22822296
Ok(match choice {
22832297
Choice::GlobalGet(i) => encode_instrs([Instruction::GlobalGet(i)]),
22842298
Choice::I32Const => encode_instrs([Instruction::I32Const(u.arbitrary()?)]),
@@ -2308,7 +2322,7 @@ impl Module {
23082322
field_ty,
23092323
u,
23102324
allow_defined_globals,
2311-
fuel.saturating_sub(1),
2325+
fuel,
23122326
)?);
23132327
}
23142328
bytes.extend(encode_instrs([Instruction::StructNew(type_idx)]));
@@ -2325,26 +2339,20 @@ impl Module {
23252339
elem_ty,
23262340
u,
23272341
allow_defined_globals,
2328-
fuel.saturating_sub(1),
2342+
fuel,
23292343
)?);
2330-
bytes.extend(const_expr_bytes(
2344+
bytes.extend(const_expr_bytes_for_array_length(
23312345
module,
2332-
ValType::I32,
23332346
u,
23342347
allow_defined_globals,
2335-
fuel.saturating_sub(1),
2348+
fuel,
23362349
)?);
23372350
bytes.extend(encode_instrs([Instruction::ArrayNew(type_idx)]));
23382351
bytes
23392352
}
23402353
Choice::ArrayNewDefault(type_idx) => {
2341-
let mut bytes = const_expr_bytes(
2342-
module,
2343-
ValType::I32,
2344-
u,
2345-
allow_defined_globals,
2346-
fuel.saturating_sub(1),
2347-
)?;
2354+
let mut bytes =
2355+
const_expr_bytes_for_array_length(module, u, allow_defined_globals, fuel)?;
23482356
bytes.extend(encode_instrs([Instruction::ArrayNewDefault(type_idx)]));
23492357
bytes
23502358
}
@@ -2359,7 +2367,7 @@ impl Module {
23592367
elem_ty,
23602368
u,
23612369
allow_defined_globals,
2362-
fuel.saturating_sub(1),
2370+
fuel,
23632371
)?);
23642372
}
23652373
bytes.extend(encode_instrs([Instruction::ArrayNewFixed {
@@ -2369,13 +2377,8 @@ impl Module {
23692377
bytes
23702378
}
23712379
Choice::RefI31 { shared } => {
2372-
let mut bytes = const_expr_bytes(
2373-
module,
2374-
ValType::I32,
2375-
u,
2376-
allow_defined_globals,
2377-
fuel.saturating_sub(1),
2378-
)?;
2380+
let mut bytes =
2381+
const_expr_bytes(module, ValType::I32, u, allow_defined_globals, fuel)?;
23792382
bytes.extend(encode_instrs([if shared {
23802383
Instruction::RefI31Shared
23812384
} else {
@@ -2389,7 +2392,7 @@ impl Module {
23892392
ValType::Ref(abstract_ref(nullable, shared, AbstractHeapType::Extern)),
23902393
u,
23912394
allow_defined_globals,
2392-
fuel.saturating_sub(1),
2395+
fuel,
23932396
)?;
23942397
bytes.extend(encode_instrs([Instruction::AnyConvertExtern]));
23952398
bytes
@@ -2400,20 +2403,21 @@ impl Module {
24002403
ValType::Ref(abstract_ref(nullable, shared, AbstractHeapType::Any)),
24012404
u,
24022405
allow_defined_globals,
2403-
fuel.saturating_sub(1),
2406+
fuel,
24042407
)?;
24052408
bytes.extend(encode_instrs([Instruction::ExternConvertAny]));
24062409
bytes
24072410
}
24082411
})
24092412
}
24102413

2414+
let mut fuel = self.config.const_expr_fuel;
24112415
Ok(ConstExpr::raw(const_expr_bytes(
24122416
self,
24132417
ty,
24142418
u,
24152419
allow_defined_globals,
2416-
MAX_CONST_EXPR_RECURSION_DEPTH,
2420+
&mut fuel,
24172421
)?))
24182422
}
24192423

0 commit comments

Comments
 (0)