Skip to content

Commit

Permalink
Merge pull request #807 from silvergasp/fuzz-serde
Browse files Browse the repository at this point in the history
fuzz: Add serde fuzzer
  • Loading branch information
schungx committed Jan 4, 2024
2 parents c5c055f + 1a92ee7 commit ed4dfaa
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ debugging = ["internals"]
## Features and dependencies required by `bin` tools: `decimal`, `metadata`, `serde`, `debugging` and [`rustyline`](https://crates.io/crates/rustyline).
bin-features = ["decimal", "metadata", "serde", "debugging", "rustyline"]
## Enable fuzzing via the [`arbitrary`](https://crates.io/crates/arbitrary) crate.
fuzz = ["arbitrary", "rust_decimal/rust-fuzz"]
fuzz = ["arbitrary", "rust_decimal/rust-fuzz", "serde"]

#! ### System Configuration Features

Expand Down
7 changes: 7 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ anyhow = "1.0.78"
arbitrary = { version = "1.3.2", features = ["derive"] }
libfuzzer-sys = "0.4"
rhai = { path = "..", features = ["fuzz", "decimal", "metadata", "debugging"] }
serde = { version = "1.0.194", features = ["derive"] }

# Prevent this from interfering with workspaces
[workspace]
Expand All @@ -31,3 +32,9 @@ name = "ast"
path = "fuzz_targets/ast.rs"
test = false
doc = false

[[bin]]
name = "fuzz_serde"
path = "fuzz_targets/fuzz_serde.rs"
test = false
doc = false
85 changes: 85 additions & 0 deletions fuzz/fuzz_targets/fuzz_serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#![no_main]
use std::{hint::black_box, time::Instant};

use arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;
use rhai::{
serde::{from_dynamic, to_dynamic},
Dynamic, Engine, OptimizationLevel, Scope,
};
use serde::{Deserialize, Serialize};

#[derive(Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize)]
struct SubStruct {
_x: f64,
}

#[derive(Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize)]
struct AllTypes {
_bool: bool,
_str: String,
_bool_vec: Vec<bool>,
_i8: i8,
_i16: i16,
_i32: i32,
_i64: i64,

_u8: u8,
_u16: u16,
_u32: u32,
_u64: u64,

_unit: (),
_tuple: (u8, u8),

_struct: SubStruct,
}

#[derive(Debug, Clone, Arbitrary)]
struct Ctx<'a> {
script: &'a str,
optimization_level: OptimizationLevel,
all_types: AllTypes,
}

fuzz_target!(|ctx: Ctx| {
let mut engine = Engine::new();

engine.set_max_string_size(1000);
engine.set_max_array_size(500);
engine.set_max_map_size(500);
engine.set_max_variables(1000);
engine.set_max_modules(1000);
engine.set_max_call_levels(10);
engine.set_max_expr_depths(50, 5);
engine.set_optimization_level(ctx.optimization_level);

// Don't actually print to stdout, but also don't optimise
// printing code away.
engine.on_debug(|x, src, pos| _ = black_box((x, src, pos)));
engine.on_print(move |s| {
_ = black_box(s);
});

// Limit the length of scripts.
let script = ctx.script.chars().take(32 * 1024).collect::<String>();

// We need fuzzing to be fast, so we'll stop executing after 1s.
let start = Instant::now();
engine.on_progress(move |_| (start.elapsed().as_millis() > 1000).then_some(Dynamic::UNIT));

let engine = engine;

let mut scope = Scope::new();
if let Ok(dynamic) = to_dynamic(ctx.all_types) {
scope.push_dynamic("x", dynamic);
}
match engine.run_with_scope(&mut scope, &script) {
Ok(_) => {
if let Some(value) = scope.get_value::<Dynamic>("x") {
let _: Result<AllTypes, _> = black_box(from_dynamic(&value));
}
}
Err(e) => _ = black_box(format!("{e}")),
}
});

0 comments on commit ed4dfaa

Please sign in to comment.