Skip to content

Commit 246ae90

Browse files
committed
WIP enable GC fuzzing
1 parent 132a490 commit 246ae90

File tree

7 files changed

+70
-37
lines changed

7 files changed

+70
-37
lines changed

crates/fuzzing/src/generators/config.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ impl<'a> Arbitrary<'a> for Config {
522522

523523
config
524524
.wasmtime
525-
.update_module_config(&mut config.module_config.config, u)?;
525+
.update_module_config(&mut config.module_config, u)?;
526526

527527
Ok(config)
528528
}
@@ -599,7 +599,7 @@ impl WasmtimeConfig {
599599
/// too.
600600
pub fn update_module_config(
601601
&mut self,
602-
config: &mut wasm_smith::Config,
602+
config: &mut ModuleConfig,
603603
u: &mut Unstructured<'_>,
604604
) -> arbitrary::Result<()> {
605605
match self.compiler_strategy {
@@ -622,10 +622,11 @@ impl WasmtimeConfig {
622622
// at this time, so if winch is selected be sure to disable wasm
623623
// proposals in `Config` to ensure that Winch can compile the
624624
// module that wasm-smith generates.
625-
config.relaxed_simd_enabled = false;
626-
config.gc_enabled = false;
627-
config.tail_call_enabled = false;
628-
config.reference_types_enabled = false;
625+
config.config.relaxed_simd_enabled = false;
626+
config.config.gc_enabled = false;
627+
config.config.tail_call_enabled = false;
628+
config.config.reference_types_enabled = false;
629+
config.function_references_enabled = false;
629630

630631
// Winch's SIMD implementations require AVX and AVX2.
631632
if self
@@ -635,7 +636,7 @@ impl WasmtimeConfig {
635636
.codegen_flag("has_avx2")
636637
.is_some_and(|value| value == "false")
637638
{
638-
config.simd_enabled = false;
639+
config.config.simd_enabled = false;
639640
}
640641

641642
// Tuning the following engine options is currently not supported
@@ -646,7 +647,7 @@ impl WasmtimeConfig {
646647
}
647648

648649
CompilerStrategy::CraneliftPulley => {
649-
config.threads_enabled = false;
650+
config.config.threads_enabled = false;
650651
}
651652
}
652653

@@ -656,7 +657,8 @@ impl WasmtimeConfig {
656657
// and for wasm threads that will require some refactoring of the
657658
// `LinearMemory` trait to bubble up the request that the linear memory
658659
// not move. Otherwise that just generates a panic right now.
659-
if config.threads_enabled || matches!(self.strategy, InstanceAllocationStrategy::Pooling(_))
660+
if config.config.threads_enabled
661+
|| matches!(self.strategy, InstanceAllocationStrategy::Pooling(_))
660662
{
661663
self.avoid_custom_unaligned_memory(u)?;
662664
}
@@ -667,31 +669,38 @@ impl WasmtimeConfig {
667669
// If the pooling allocator is used, do not allow shared memory to
668670
// be created. FIXME: see
669671
// https://github.com/bytecodealliance/wasmtime/issues/4244.
670-
config.threads_enabled = false;
672+
config.config.threads_enabled = false;
671673

672674
// Ensure the pooling allocator can support the maximal size of
673675
// memory, picking the smaller of the two to win.
674676
let min_bytes = config
677+
.config
675678
.max_memory32_bytes
676679
// memory64_bytes is a u128, but since we are taking the min
677680
// we can truncate it down to a u64.
678-
.min(config.max_memory64_bytes.try_into().unwrap_or(u64::MAX));
681+
.min(
682+
config
683+
.config
684+
.max_memory64_bytes
685+
.try_into()
686+
.unwrap_or(u64::MAX),
687+
);
679688
let mut min = min_bytes.min(pooling.max_memory_size as u64);
680689
if let MemoryConfig::Normal(cfg) = &self.memory_config {
681690
min = min.min(cfg.memory_reservation.unwrap_or(0));
682691
}
683692
pooling.max_memory_size = min as usize;
684-
config.max_memory32_bytes = min;
685-
config.max_memory64_bytes = min as u128;
693+
config.config.max_memory32_bytes = min;
694+
config.config.max_memory64_bytes = min as u128;
686695

687696
// If traps are disallowed then memories must have at least one page
688697
// of memory so if we still are only allowing 0 pages of memory then
689698
// increase that to one here.
690-
if config.disallow_traps {
699+
if config.config.disallow_traps {
691700
if pooling.max_memory_size < (1 << 16) {
692701
pooling.max_memory_size = 1 << 16;
693-
config.max_memory32_bytes = 1 << 16;
694-
config.max_memory64_bytes = 1 << 16;
702+
config.config.max_memory32_bytes = 1 << 16;
703+
config.config.max_memory64_bytes = 1 << 16;
695704
if let MemoryConfig::Normal(cfg) = &mut self.memory_config {
696705
match &mut cfg.memory_reservation {
697706
Some(size) => *size = (*size).max(pooling.max_memory_size as u64),
@@ -707,13 +716,13 @@ impl WasmtimeConfig {
707716

708717
// Don't allow too many linear memories per instance since massive
709718
// virtual mappings can fail to get allocated.
710-
config.min_memories = config.min_memories.min(10);
711-
config.max_memories = config.max_memories.min(10);
719+
config.config.min_memories = config.config.min_memories.min(10);
720+
config.config.max_memories = config.config.max_memories.min(10);
712721

713722
// Force this pooling allocator to always be able to accommodate the
714723
// module that may be generated.
715-
pooling.total_memories = config.max_memories as u32;
716-
pooling.total_tables = config.max_tables as u32;
724+
pooling.total_memories = config.config.max_memories as u32;
725+
pooling.total_tables = config.config.max_tables as u32;
717726
}
718727

719728
if !self.signals_based_traps {
@@ -723,7 +732,7 @@ impl WasmtimeConfig {
723732
// fixable with some more work on the bounds-checks side of things
724733
// to do a full bounds check even on static memories, but that's
725734
// left for a future PR.
726-
config.threads_enabled = false;
735+
config.config.threads_enabled = false;
727736

728737
// Spectre-based heap mitigations require signal handlers so this
729738
// must always be disabled if signals-based traps are disabled.

crates/fuzzing/src/generators/module.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ impl<'a> Arbitrary<'a> for ModuleConfig {
4141
let _ = config.relaxed_simd_enabled;
4242
let _ = config.tail_call_enabled;
4343
let _ = config.extended_const_enabled;
44+
let _ = config.gc_enabled;
4445
config.exceptions_enabled = false;
45-
config.gc_enabled = false;
4646
config.custom_page_sizes_enabled = u.arbitrary()?;
4747
config.wide_arithmetic_enabled = u.arbitrary()?;
4848
config.memory64_enabled = u.ratio(1, 20)?;

crates/fuzzing/src/generators/value.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ impl PartialEq for DiffValue {
267267
}
268268
(Self::FuncRef { null: a }, Self::FuncRef { null: b }) => a == b,
269269
(Self::ExternRef { null: a }, Self::ExternRef { null: b }) => a == b,
270+
(Self::AnyRef { null: a }, Self::AnyRef { null: b }) => a == b,
270271
_ => false,
271272
}
272273
}
@@ -302,7 +303,7 @@ impl TryFrom<wasmtime::ValType> for DiffValueType {
302303
(true, HeapType::Any) => Ok(Self::AnyRef),
303304
(true, HeapType::I31) => Ok(Self::AnyRef),
304305
(true, HeapType::None) => Ok(Self::AnyRef),
305-
_ => Err("non-funcref and non-externref reference types are not supported yet"),
306+
_ => Err("non-null reference types are not supported yet"),
306307
},
307308
}
308309
}

crates/fuzzing/src/oracles.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,11 @@ pub fn instantiate_with_dummy(store: &mut Store<StoreLimits>, module: &Module) -
369369
// Creation of imports can fail due to resource limit constraints, and then
370370
// instantiation can naturally fail for a number of reasons as well. Bundle
371371
// the two steps together to match on the error below.
372-
let instance =
373-
dummy::dummy_linker(store, module).and_then(|l| l.instantiate(&mut *store, module));
372+
let linker = dummy::dummy_linker(store, module);
373+
if let Err(e) = &linker {
374+
log::warn!("failed to create dummy linker: {e:?}");
375+
}
376+
let instance = linker.and_then(|l| l.instantiate(&mut *store, module));
374377
unwrap_instance(store, instance)
375378
}
376379

crates/fuzzing/src/oracles/diff_wasmtime.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ impl WasmtimeEngine {
2626
) -> arbitrary::Result<Self> {
2727
let mut new_config = u.arbitrary::<WasmtimeConfig>()?;
2828
new_config.compiler_strategy = compiler_strategy;
29-
new_config.update_module_config(&mut config.module_config.config, u)?;
29+
new_config.update_module_config(&mut config.module_config, u)?;
3030
new_config.make_compatible_with(&config.wasmtime);
3131

3232
let config = generators::Config {
3333
wasmtime: new_config,
3434
module_config: config.module_config.clone(),
3535
};
36+
log::debug!("Created new Wasmtime differential engine with config: {config:?}");
37+
3638
Ok(Self { config })
3739
}
3840
}
@@ -118,11 +120,10 @@ impl WasmtimeInstance {
118120

119121
globals
120122
.into_iter()
121-
.map(|(name, global)| {
122-
(
123-
name,
124-
global.ty(&self.store).content().clone().try_into().unwrap(),
125-
)
123+
.filter_map(|(name, global)| {
124+
DiffValueType::try_from(global.ty(&self.store).content().clone())
125+
.map(|ty| (name, ty))
126+
.ok()
126127
})
127128
.collect()
128129
}

crates/wasmtime/src/runtime/linker.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
Instance, Module, StoreContextMut, Val, ValRaw, ValType,
99
};
1010
use alloc::sync::Arc;
11-
use core::fmt;
11+
use core::fmt::{self, Debug};
1212
use core::marker;
1313
#[cfg(feature = "async")]
1414
use core::{future::Future, pin::Pin};
@@ -90,6 +90,12 @@ pub struct Linker<T> {
9090
_marker: marker::PhantomData<fn() -> T>,
9191
}
9292

93+
impl<T> Debug for Linker<T> {
94+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95+
f.debug_struct("Linker").finish_non_exhaustive()
96+
}
97+
}
98+
9399
impl<T> Clone for Linker<T> {
94100
fn clone(&self) -> Linker<T> {
95101
Linker {

fuzz/fuzz_targets/differential.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![no_main]
22

3-
use libfuzzer_sys::arbitrary::{Result, Unstructured};
3+
use libfuzzer_sys::arbitrary::{self, Result, Unstructured};
44
use libfuzzer_sys::fuzz_target;
55
use std::sync::atomic::AtomicUsize;
66
use std::sync::atomic::Ordering::SeqCst;
@@ -80,12 +80,15 @@ fn execute_one(data: &[u8]) -> Result<()> {
8080
return Ok(());
8181
}
8282
};
83+
84+
log::trace!("Building LHS engine");
8385
let mut lhs = match engine::build(&mut u, lhs, &mut config)? {
8486
Some(engine) => engine,
8587
// The chosen engine does not have support compiled into the fuzzer,
8688
// discard this test case.
8789
None => return Ok(()),
8890
};
91+
log::debug!("lhs engine: {}", lhs.name());
8992

9093
// Using the now-legalized module configuration generate the Wasm module;
9194
// this is specified by either the ALLOWED_MODULES environment variable or a
@@ -118,11 +121,11 @@ fn execute_one(data: &[u8]) -> Result<()> {
118121
log_wasm(&wasm);
119122

120123
// Instantiate the generated wasm file in the chosen differential engine.
121-
log::debug!("lhs engine: {}", lhs.name());
122124
let lhs_instance = lhs.instantiate(&wasm);
123125
STATS.bump_engine(lhs.name());
124126

125127
// Always use Wasmtime as the second engine to instantiate within.
128+
log::debug!("Building RHS Wasmtime");
126129
let rhs_store = config.to_store();
127130
let rhs_module = wasmtime::Module::new(rhs_store.engine(), &wasm).unwrap();
128131
let rhs_instance = WasmtimeInstance::new(rhs_store, rhs_module);
@@ -143,12 +146,22 @@ fn execute_one(data: &[u8]) -> Result<()> {
143146
loop {
144147
let arguments = signature
145148
.params()
146-
.map(|t| DiffValue::arbitrary_of_type(&mut u, t.try_into().unwrap()))
149+
.map(|ty| {
150+
let ty = ty
151+
.try_into()
152+
.map_err(|_| arbitrary::Error::IncorrectFormat)?;
153+
DiffValue::arbitrary_of_type(&mut u, ty)
154+
})
147155
.collect::<Result<Vec<_>>>()?;
148156
let result_tys = signature
149157
.results()
150-
.map(|t| DiffValueType::try_from(t).unwrap())
151-
.collect::<Vec<_>>();
158+
.map(|ty| {
159+
let ty: wasmtime::ValType = ty
160+
.try_into()
161+
.map_err(|_| arbitrary::Error::IncorrectFormat)?;
162+
DiffValueType::try_from(ty).map_err(|_| arbitrary::Error::IncorrectFormat)
163+
})
164+
.collect::<Result<Vec<_>>>()?;
152165
let ok = differential(
153166
lhs_instance.as_mut(),
154167
lhs.as_ref(),

0 commit comments

Comments
 (0)