Skip to content

Commit 9c61016

Browse files
authored
Restrict value sizes in component_api fuzzer (#13046)
This commit adds a fuel counter when creating values in the `component_api` fuzzer to ensure the value isn't too large at runtime. This fixes a fuzz-bug where the created value exceeded the value of being able to fit in memory, causing a fuzz failure.
1 parent a8f6070 commit 9c61016

1 file changed

Lines changed: 38 additions & 13 deletions

File tree

crates/fuzzing/src/oracles/component_api.rs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,14 @@ const MAX_LIST_LENGTH: u32 = 10;
3131
const MAX_ITERS: usize = 1_000;
3232

3333
/// Generate an arbitrary instance of the specified type.
34-
fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrary::Result<Val> {
34+
fn arbitrary_val(
35+
ty: &component::Type,
36+
fuel: &mut u32,
37+
input: &mut Unstructured,
38+
) -> arbitrary::Result<Val> {
3539
use component::Type;
3640

41+
*fuel = fuel.saturating_sub(1);
3742
Ok(match ty {
3843
Type::Bool => Val::Bool(input.arbitrary()?),
3944
Type::S8 => Val::S8(input.arbitrary()?),
@@ -47,11 +52,22 @@ fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrary::R
4752
Type::Float32 => Val::Float32(input.arbitrary()?),
4853
Type::Float64 => Val::Float64(input.arbitrary()?),
4954
Type::Char => Val::Char(input.arbitrary()?),
50-
Type::String => Val::String(input.arbitrary()?),
55+
Type::String => {
56+
let string = if *fuel == 0 {
57+
String::new()
58+
} else {
59+
input.arbitrary()?
60+
};
61+
*fuel = fuel.saturating_sub(string.len() as u32);
62+
Val::String(string)
63+
}
5164
Type::List(list) => {
5265
let mut values = Vec::new();
5366
input.arbitrary_loop(Some(MIN_LIST_LENGTH), Some(MAX_LIST_LENGTH), |input| {
54-
values.push(arbitrary_val(&list.ty(), input)?);
67+
if *fuel == 0 {
68+
return Ok(ControlFlow::Break(()));
69+
}
70+
values.push(arbitrary_val(&list.ty(), fuel, input)?);
5571

5672
Ok(ControlFlow::Continue(()))
5773
})?;
@@ -61,20 +77,25 @@ fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrary::R
6177
Type::Record(record) => Val::Record(
6278
record
6379
.fields()
64-
.map(|field| Ok((field.name.to_string(), arbitrary_val(&field.ty, input)?)))
80+
.map(|field| {
81+
Ok((
82+
field.name.to_string(),
83+
arbitrary_val(&field.ty, fuel, input)?,
84+
))
85+
})
6586
.collect::<arbitrary::Result<_>>()?,
6687
),
6788
Type::Tuple(tuple) => Val::Tuple(
6889
tuple
6990
.types()
70-
.map(|ty| arbitrary_val(&ty, input))
91+
.map(|ty| arbitrary_val(&ty, fuel, input))
7192
.collect::<arbitrary::Result<_>>()?,
7293
),
7394
Type::Variant(variant) => {
7495
let cases = variant.cases().collect::<Vec<_>>();
7596
let case = input.choose(&cases)?;
7697
let payload = match &case.ty {
77-
Some(ty) => Some(Box::new(arbitrary_val(ty, input)?)),
98+
Some(ty) => Some(Box::new(arbitrary_val(ty, fuel, input)?)),
7899
None => None,
79100
};
80101
Val::Variant(case.name.to_string(), payload)
@@ -88,19 +109,19 @@ fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrary::R
88109
let discriminant = input.int_in_range(0..=1)?;
89110
Val::Option(match discriminant {
90111
0 => None,
91-
1 => Some(Box::new(arbitrary_val(&option.ty(), input)?)),
112+
1 => Some(Box::new(arbitrary_val(&option.ty(), fuel, input)?)),
92113
_ => unreachable!(),
93114
})
94115
}
95116
Type::Result(result) => {
96117
let discriminant = input.int_in_range(0..=1)?;
97118
Val::Result(match discriminant {
98119
0 => Ok(match result.ok() {
99-
Some(ty) => Some(Box::new(arbitrary_val(&ty, input)?)),
120+
Some(ty) => Some(Box::new(arbitrary_val(&ty, fuel, input)?)),
100121
None => None,
101122
}),
102123
1 => Err(match result.err() {
103-
Some(ty) => Some(Box::new(arbitrary_val(&ty, input)?)),
124+
Some(ty) => Some(Box::new(arbitrary_val(&ty, fuel, input)?)),
104125
None => None,
105126
}),
106127
_ => unreachable!(),
@@ -121,8 +142,11 @@ fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrary::R
121142
Type::Map(map) => {
122143
let mut pairs = Vec::new();
123144
input.arbitrary_loop(Some(MIN_LIST_LENGTH), Some(MAX_LIST_LENGTH), |input| {
124-
let key = arbitrary_val(&map.key(), input)?;
125-
let value = arbitrary_val(&map.value(), input)?;
145+
if *fuel == 0 {
146+
return Ok(ControlFlow::Break(()));
147+
}
148+
let key = arbitrary_val(&map.key(), fuel, input)?;
149+
let value = arbitrary_val(&map.value(), fuel, input)?;
126150
pairs.push((key, value));
127151
Ok(ControlFlow::Continue(()))
128152
})?;
@@ -369,13 +393,14 @@ pub fn dynamic_component_api_target(input: &mut arbitrary::Unstructured) -> arbi
369393

370394
let mut iters = 0..MAX_ITERS;
371395
while iters.next().is_some() && input.arbitrary()? {
396+
let mut fuel = 10_000;
372397
let params = ty
373398
.params()
374-
.map(|(_, ty)| arbitrary_val(&ty, input))
399+
.map(|(_, ty)| arbitrary_val(&ty, &mut fuel, input))
375400
.collect::<arbitrary::Result<Vec<_>>>()?;
376401
let results = ty
377402
.results()
378-
.map(|ty| arbitrary_val(&ty, input))
403+
.map(|ty| arbitrary_val(&ty, &mut fuel, input))
379404
.collect::<arbitrary::Result<Vec<_>>>()?;
380405

381406
*store.data_mut() = (params.clone(), Some(results.clone()));

0 commit comments

Comments
 (0)