mirror of https://github.com/boa-dev/boa.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
2.3 KiB
75 lines
2.3 KiB
2 years ago
|
use boa_ast::{
|
||
|
visitor::{VisitWith, VisitorMut},
|
||
|
Expression, StatementList,
|
||
|
};
|
||
|
use boa_interner::{Interner, Sym};
|
||
|
use libfuzzer_sys::arbitrary;
|
||
|
use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};
|
||
|
use std::fmt::{Debug, Formatter};
|
||
|
use std::ops::ControlFlow;
|
||
|
|
||
|
/// Context for performing fuzzing. This structure contains both the generated AST as well as the
|
||
|
/// context used to resolve the symbols therein.
|
||
|
pub struct FuzzData {
|
||
|
pub interner: Interner,
|
||
|
pub ast: StatementList,
|
||
|
}
|
||
|
|
||
|
impl<'a> Arbitrary<'a> for FuzzData {
|
||
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
||
|
let mut interner = Interner::with_capacity(8);
|
||
|
let mut syms_available = Vec::with_capacity(8);
|
||
|
for c in 'a'..='h' {
|
||
|
syms_available.push(interner.get_or_intern(&*String::from(c)));
|
||
|
}
|
||
|
|
||
|
let mut ast = StatementList::arbitrary(u)?;
|
||
|
|
||
|
struct FuzzReplacer<'a, 's, 'u> {
|
||
|
syms: &'s [Sym],
|
||
|
u: &'u mut Unstructured<'a>,
|
||
|
}
|
||
|
impl<'a, 's, 'u, 'ast> VisitorMut<'ast> for FuzzReplacer<'a, 's, 'u> {
|
||
|
type BreakTy = arbitrary::Error;
|
||
|
|
||
|
// TODO arbitrary strings literals?
|
||
|
|
||
|
fn visit_expression_mut(
|
||
|
&mut self,
|
||
|
node: &'ast mut Expression,
|
||
|
) -> ControlFlow<Self::BreakTy> {
|
||
|
if matches!(node, Expression::FormalParameterList(_)) {
|
||
|
match self.u.arbitrary() {
|
||
|
Ok(id) => *node = Expression::Identifier(id),
|
||
|
Err(e) => return ControlFlow::Break(e),
|
||
|
}
|
||
|
}
|
||
|
node.visit_with_mut(self)
|
||
|
}
|
||
|
|
||
|
fn visit_sym_mut(&mut self, node: &'ast mut Sym) -> ControlFlow<Self::BreakTy> {
|
||
|
*node = self.syms[node.get() % self.syms.len()];
|
||
|
ControlFlow::Continue(())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let mut replacer = FuzzReplacer {
|
||
|
syms: &syms_available,
|
||
|
u,
|
||
|
};
|
||
|
if let ControlFlow::Break(e) = replacer.visit_statement_list_mut(&mut ast) {
|
||
|
Err(e)
|
||
|
} else {
|
||
|
Ok(Self { interner, ast })
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Debug for FuzzData {
|
||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||
|
f.debug_struct("FuzzData")
|
||
|
.field("ast", &self.ast)
|
||
|
.finish_non_exhaustive()
|
||
|
}
|
||
|
}
|