crftng-intrprtrs/gc/fuzz/fuzz_targets/fuzz_target_1.rs

84 lines
2.1 KiB
Rust

#![no_main]
use gc::{self, gc_ref::GcRef, test_utils::GotDropped, trace::GCTrace};
use libfuzzer_sys::fuzz_target;
use std::cell::RefCell;
use libfuzzer_sys::arbitrary;
#[derive(arbitrary::Arbitrary, Debug)]
struct ChildIDx(usize);
impl ChildIDx {
fn choose<'a, T>(&self, choices: &'a [T]) -> Option<&'a T> {
let idx = self.choose_index(choices.len())?;
Some(choices.get(idx).unwrap())
}
fn choose_index(&self, len: usize) -> Option<usize> {
(len != 0).then(|| self.0 % len)
}
}
#[derive(arbitrary::Arbitrary, Debug)]
enum GraphExplore {
ExploreChild(ChildIDx, Box<GraphExplore>),
Stop,
}
#[derive(arbitrary::Arbitrary, Debug)]
enum Op {
AddLink(GraphExplore, Option<GraphExplore>),
RemoveChild(GraphExplore, ChildIDx),
CollectGarbage,
}
#[derive(GCTrace, Default)]
struct Node {
children: Vec<GCNode>,
}
type GCNode = GcRef<RefCell<Node>>;
impl Node {
fn explore(node: GCNode, instructions: GraphExplore) -> GCNode {
match instructions {
GraphExplore::ExploreChild(child_idx, child_instructions) => {
let child = child_idx
.choose(&*node.borrow().children)
.map(|v| v.clone());
child
.map(|c| Node::explore(c, *child_instructions))
.unwrap_or(node)
}
GraphExplore::Stop => node,
}
}
}
fuzz_target!(|ops: Vec<Op>| {
let mut allocator = gc::allocator::GCAllocator::default();
let root: GCNode = allocator.alloc(RefCell::default());
for op in ops {
match op {
Op::AddLink(parent_path, child_path) => {
let child = child_path
.map(|c| Node::explore(root.clone(), c))
.unwrap_or_else(|| allocator.alloc(RefCell::default()));
let parent = Node::explore(root.clone(), parent_path);
parent.borrow_mut().children.push(child);
}
Op::RemoveChild(parent_path, child_idx) => {
let parent = Node::explore(root.clone(), parent_path);
let children = &mut parent.borrow_mut().children;
let idx = child_idx.choose_index(children.len());
if let Some(idx) = idx {
children.remove(idx);
}
}
Op::CollectGarbage => unsafe { allocator.gc(&root) },
}
}
unsafe { allocator.gc(&()) };
});