Rust编写的JavaScript引擎,该项目是一个试验性质的项目。
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.
 
 

98 lines
2.9 KiB

use arbitrary::{Arbitrary, Unstructured};
use boa_ast::{
visitor::{VisitWith, VisitorMut},
Expression, StatementList,
};
use boa_interner::{Interner, Sym, ToInternedString};
use std::{
fmt::{Debug, Formatter},
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()
}
}
#[expect(dead_code)]
pub struct FuzzSource {
pub interner: Interner,
pub source: String,
}
impl<'a> Arbitrary<'a> for FuzzSource {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let data = FuzzData::arbitrary(u)?;
let source = data.ast.to_interned_string(&data.interner);
Ok(Self {
interner: data.interner,
source,
})
}
}
impl Debug for FuzzSource {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("Fuzzed source:\n{}", self.source))
}
}