|
|
|
#![no_main]
|
|
|
|
|
|
|
|
mod common;
|
|
|
|
|
|
|
|
use crate::common::FuzzData;
|
|
|
|
use boa_interner::ToInternedString;
|
|
|
|
use boa_parser::Parser;
|
|
|
|
use libfuzzer_sys::fuzz_target;
|
|
|
|
use libfuzzer_sys::Corpus;
|
|
|
|
use std::error::Error;
|
|
|
|
use std::io::Cursor;
|
|
|
|
|
|
|
|
/// Fuzzer test harness. This function accepts the arbitrary AST and performs the fuzzing operation.
|
|
|
|
///
|
|
|
|
/// See [README.md](../README.md) for details on the design of this fuzzer.
|
|
|
|
fn do_fuzz(mut data: FuzzData) -> Result<(), Box<dyn Error>> {
|
|
|
|
let original = data.ast.to_interned_string(&data.interner);
|
|
|
|
|
|
|
|
let mut parser = Parser::new(Cursor::new(&original));
|
|
|
|
|
|
|
|
let before = data.interner.len();
|
|
|
|
// For a variety of reasons, we may not actually produce valid code here (e.g., nameless function).
|
|
|
|
// Fail fast and only make the next checks if we were valid.
|
Module parsing (#2411)
I'm creating this draft PR, since I wanted to have some early feedback, and because I though I would have time to finish it last week, but I got caught up with other stuff. Feel free to contribute :)
The main thing here is that I have divided `eval()`, `parse()` and similar functions so that they can decide if they are parsing scripts or modules. Let me know your thoughts.
Then, I was checking the import & export parsing, and I noticed we are using `TokenKind::Identifier` for `IdentifierName`, so I changed that name. An `Identifier` is an `IdentifierName` that isn't a `ReservedWord`. This means we should probably also adapt all `IdentifierReference`, `BindingIdentifier` and so on parsing. I already created an `Identifier` parser.
Something interesting there is that `await` is not a valid `Identifier` if the goal symbol is `Module`, as you can see in the [spec](https://tc39.es/ecma262/#prod-LabelIdentifier), but currently we don't have that information in the `InputElement` enumeration, we only have `Div`, `RegExp` and `TemplateTail`. How could we approach this?
Co-authored-by: jedel1043 <jedel0124@gmail.com>
2 years ago
|
|
|
if let Ok(first) = parser.parse_script(&mut data.interner) {
|
|
|
|
let after_first = data.interner.len();
|
|
|
|
let first_interned = first.to_interned_string(&data.interner);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
before,
|
|
|
|
after_first,
|
|
|
|
"The number of interned symbols changed; a new string was read.\nBefore:\n{}\nAfter:\n{}\nBefore (AST):\n{:#?}\nAfter (AST):\n{:#?}",
|
|
|
|
original,
|
|
|
|
first_interned,
|
|
|
|
data.ast,
|
|
|
|
first
|
|
|
|
);
|
|
|
|
let mut parser = Parser::new(Cursor::new(&first_interned));
|
|
|
|
|
|
|
|
// Now, we most assuredly should produce valid code. It has already gone through a first pass.
|
|
|
|
let second = parser
|
Module parsing (#2411)
I'm creating this draft PR, since I wanted to have some early feedback, and because I though I would have time to finish it last week, but I got caught up with other stuff. Feel free to contribute :)
The main thing here is that I have divided `eval()`, `parse()` and similar functions so that they can decide if they are parsing scripts or modules. Let me know your thoughts.
Then, I was checking the import & export parsing, and I noticed we are using `TokenKind::Identifier` for `IdentifierName`, so I changed that name. An `Identifier` is an `IdentifierName` that isn't a `ReservedWord`. This means we should probably also adapt all `IdentifierReference`, `BindingIdentifier` and so on parsing. I already created an `Identifier` parser.
Something interesting there is that `await` is not a valid `Identifier` if the goal symbol is `Module`, as you can see in the [spec](https://tc39.es/ecma262/#prod-LabelIdentifier), but currently we don't have that information in the `InputElement` enumeration, we only have `Div`, `RegExp` and `TemplateTail`. How could we approach this?
Co-authored-by: jedel1043 <jedel0124@gmail.com>
2 years ago
|
|
|
.parse_script(&mut data.interner)
|
|
|
|
.expect("Could not parse the first-pass interned copy.");
|
|
|
|
let second_interned = second.to_interned_string(&data.interner);
|
|
|
|
let after_second = data.interner.len();
|
|
|
|
assert_eq!(
|
|
|
|
after_first,
|
|
|
|
after_second,
|
|
|
|
"The number of interned symbols changed; a new string was read.\nBefore:\n{}\nAfter:\n{}\nBefore (AST):\n{:#?}\nAfter (AST):\n{:#?}",
|
|
|
|
first_interned,
|
|
|
|
second_interned,
|
|
|
|
first,
|
|
|
|
second
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
first,
|
|
|
|
second,
|
|
|
|
"Expected the same AST after two intern passes, but found dissimilar.\nOriginal:\n{}\nFirst:\n{}\nSecond:\n{}",
|
|
|
|
original,
|
|
|
|
first_interned,
|
|
|
|
second_interned,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fuzz harness wrapper to expose it to libfuzzer (and thus cargo-fuzz)
|
|
|
|
// See: https://rust-fuzz.github.io/book/cargo-fuzz.html
|
|
|
|
fuzz_target!(|data: FuzzData| -> Corpus {
|
|
|
|
if do_fuzz(data).is_ok() {
|
|
|
|
Corpus::Keep
|
|
|
|
} else {
|
|
|
|
Corpus::Reject
|
|
|
|
}
|
|
|
|
});
|