Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cranelift/codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ smallvec = { workspace = true }
regalloc2 = { version = "0.6.1", features = ["checker"] }
souper-ir = { version = "2.1.0", optional = true }
sha2 = { version = "0.10.2", optional = true }
arbitrary = { version = "1.2.3", optional = true } # this will be replaced with the control plane (maybe located cranelift-fuzzgen).
# It is a goal of the cranelift-codegen crate to have minimal external dependencies.
# Please don't add any unless they are essential to the task of creating binary
# machine code. Integration tests that need external dependencies can be
Expand Down Expand Up @@ -113,6 +114,9 @@ isle-errors = ["cranelift-isle/fancy-errors"]
# inspection, rather than inside of target/.
isle-in-source-tree = []

# Enable targeted fuzzing of compiler internal decisions
chaos_mode = ["dep:arbitrary"]

[badges]
maintenance = { status = "experimental" }

Expand Down
18 changes: 18 additions & 0 deletions cranelift/codegen/src/chaos_mode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
static mut EMPTY: &'static [u8] = &[];
static mut UNSTRUCTURED: &'static mut [u8] = EMPTY;

pub fn init_unstructured(data: &[u8]) {
unsafe {
UNSTRUCTURED = data;
}
}

pub fn drop_unstructured() {
unsafe {
UNSTRUCTURED = EMPTY;
}
}

pub fn get_mut<'a>() -> &'a mut [u8] {
UNSTRUCTURED
}
6 changes: 5 additions & 1 deletion cranelift/codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ pub use cranelift_entity as entity;
pub use gimli;

#[macro_use]
mod machinst;
#[allow(missing_docs)] // should be removed again just to test the poc
pub mod machinst;

#[cfg(feature = "chaos_mode")]
pub mod chaos_mode;

pub mod binemit;
pub mod cfg_printer;
Expand Down
34 changes: 33 additions & 1 deletion cranelift/codegen/src/machinst/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,26 @@ impl<I: VCodeInst> MachBuffer<I> {
}

fn optimize_branches(&mut self) {
#[cfg(feature = "chaos_mode")]
{
// I think 2 different optimize function with (#[cfg(fuzzing)] / #[cfg(not(fuzzing))])
// would not work, because there would be no way to do bisection

// Get the raw data from the fuzzer: we need some kind of "dependency injection"
let raw_data: Vec<u8> = vec![1, 2, 3];

// Wrap that raw data in an `Unstructured`.
let mut unstructured = arbitrary::Unstructured::new(&raw_data);

// Generate an arbitrary boolean to skip optimizing or not... this value would
// later be generated by our control plane, to have more control for bisection
if let Ok(value) = arbitrary::Arbitrary::arbitrary(&mut unstructured) {
if value {
return ();
}
}
}

self.lazily_clear_labels_at_tail();
// Invariants valid at this point.

Expand Down Expand Up @@ -1673,7 +1693,7 @@ impl<I: VCodeInst> TextSectionBuilder for MachTextSectionBuilder<I> {
}

// We use an actual instruction definition to do tests, so we depend on the `arm64` feature here.
#[cfg(all(test, feature = "arm64"))]
#[cfg(any(all(test, feature = "arm64"), feature = "chaos_mode"))]
mod test {
use cranelift_entity::EntityRef as _;

Expand Down Expand Up @@ -1785,6 +1805,11 @@ mod test {

#[test]
fn test_island() {
test_island_body()
}

// the idea is that this would be available for testing and fuzzing: maybe it's better to define own test cases for fuzzing
pub fn test_island_body() {
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new();
let mut state = Default::default();
Expand Down Expand Up @@ -2104,3 +2129,10 @@ mod test {
);
}
}

// is this th right way to go or should there be a more e2e approach?
#[cfg(feature = "chaos_mode")]
pub fn test_fuzzing() {
// maybe pass in a seed?
test::test_island_body() // call the test cases that should also work in chaos mode
}
8 changes: 8 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ component-fuzz-util = { workspace = true }
[features]
default = ['fuzz-spec-interpreter']
fuzz-spec-interpreter = ['wasmtime-fuzzing/fuzz-spec-interpreter']
chaos_mode = ["cranelift-codegen/chaos_mode"]

[[bin]]
name = "compile"
Expand All @@ -55,6 +56,13 @@ path = "fuzz_targets/api_calls.rs"
test = false
doc = false

[[bin]]
name = "chaos_mode"
path = "fuzz_targets/chaos_mode.rs"
test = false
doc = false
required-features = ["chaos_mode"]

[[bin]]
name = "differential"
path = "fuzz_targets/differential.rs"
Expand Down
12 changes: 12 additions & 0 deletions fuzz/fuzz_targets/chaos_mode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;

use cranelift_codegen::machinst::buffer::test_fuzzing;

// one fuzz target per crate / module / test?
fuzz_target!(|data: &[u8]| {
cranelift_codegen::chaos_mode::init_unstructured(data);
test_fuzzing();
cranelift_codegen::chaos_mode::drop_unstructured(data);
});