mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-28 21:41:35 +00:00
parser: add fuzzer
This commit is contained in:
parent
241c60143e
commit
b62d558c21
6
.github/workflows/rust.yml
vendored
6
.github/workflows/rust.yml
vendored
@ -37,6 +37,7 @@ jobs:
|
|||||||
package: [
|
package: [
|
||||||
rinja, rinja_actix, rinja_axum, rinja_derive, rinja_derive_standalone,
|
rinja, rinja_actix, rinja_axum, rinja_derive, rinja_derive_standalone,
|
||||||
rinja_parser, rinja_rocket, rinja_warp, testing, examples/actix-web-app,
|
rinja_parser, rinja_rocket, rinja_warp, testing, examples/actix-web-app,
|
||||||
|
fuzz_parser
|
||||||
]
|
]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@ -65,7 +66,8 @@ jobs:
|
|||||||
set -eu
|
set -eu
|
||||||
for PKG in \
|
for PKG in \
|
||||||
rinja rinja_actix rinja_axum rinja_derive rinja_derive_standalone \
|
rinja rinja_actix rinja_axum rinja_derive rinja_derive_standalone \
|
||||||
rinja_parser rinja_rocket rinja_warp testing examples/actix-web-app
|
rinja_parser rinja_rocket rinja_warp testing examples/actix-web-app \
|
||||||
|
fuzz_parser
|
||||||
do
|
do
|
||||||
cd "$PKG"
|
cd "$PKG"
|
||||||
echo "Testing: $PKG"
|
echo "Testing: $PKG"
|
||||||
@ -79,7 +81,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@master
|
- uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: "1.71.0"
|
toolchain: "1.71.1"
|
||||||
- run: cargo check --lib -p rinja --all-features
|
- run: cargo check --lib -p rinja --all-features
|
||||||
|
|
||||||
Audit:
|
Audit:
|
||||||
|
19
fuzz_parser/Cargo.toml
Normal file
19
fuzz_parser/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "fuzz_parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rinja_parser = { path = "../rinja_parser" }
|
||||||
|
|
||||||
|
arbitrary = { version = "1.3.2", features = ["derive"] }
|
||||||
|
pretty-error-debug = "0.3.0"
|
||||||
|
thiserror = "1.0.63"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [".", "fuzz"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = 1
|
29
fuzz_parser/README.md
Normal file
29
fuzz_parser/README.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Rinja Parser Fuzzer
|
||||||
|
|
||||||
|
First install `cargo-fuzz` and rust-nightly (once):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install cargo-fuzz
|
||||||
|
rustup install nightly
|
||||||
|
```
|
||||||
|
|
||||||
|
Then execute in this folder:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
RUST_BACKTRACE=1 nice cargo +nightly fuzz run fuzz
|
||||||
|
```
|
||||||
|
|
||||||
|
The execution won't stop, but continue until you kill it with ctrl+c.
|
||||||
|
Or until it finds a panic.
|
||||||
|
If the execution found a panic, then a file with the input scenario is written, e.g.
|
||||||
|
`fuzz/artifacts/fuzz/crash-4184…`.
|
||||||
|
To get more information about the failed scenario, run or debug this command with the given path:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run -- fuzz/artifacts/fuzz/crash-4184…
|
||||||
|
```
|
||||||
|
|
||||||
|
Find more information about fuzzing here:
|
||||||
|
|
||||||
|
* `cargo fuzz help run`
|
||||||
|
* <https://rust-fuzz.github.io/book/cargo-fuzz.html>
|
2
fuzz_parser/fuzz/.gitignore
vendored
Normal file
2
fuzz_parser/fuzz/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/artifacts/
|
||||||
|
/corpus/
|
14
fuzz_parser/fuzz/Cargo.toml
Normal file
14
fuzz_parser/fuzz/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "fuzz"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
cargo-fuzz = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fuzz_parser = { path = ".." }
|
||||||
|
|
||||||
|
libfuzzer-sys = "0.4.7"
|
7
fuzz_parser/fuzz/src/main.rs
Normal file
7
fuzz_parser/fuzz/src/main.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||||
|
if let Ok(scenario) = fuzz_parser::Scenario::new(data) {
|
||||||
|
let _ = scenario.run();
|
||||||
|
}
|
||||||
|
});
|
47
fuzz_parser/src/lib.rs
Normal file
47
fuzz_parser/src/lib.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use arbitrary::{Arbitrary, Unstructured};
|
||||||
|
use rinja_parser::{Ast, Syntax};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Scenario<'a> {
|
||||||
|
syntax: Syntax<'a>,
|
||||||
|
src: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Scenario<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> Result<Self, arbitrary::Error> {
|
||||||
|
let mut data = Unstructured::new(data);
|
||||||
|
|
||||||
|
let syntax = ArbitrarySyntax::arbitrary(&mut data)?;
|
||||||
|
let _syntax = syntax.as_syntax();
|
||||||
|
// FIXME: related issue: <https://github.com/rinja-rs/rinja/issues/138>
|
||||||
|
let syntax = Syntax::default();
|
||||||
|
|
||||||
|
let src = <&str>::arbitrary_take_rest(data)?;
|
||||||
|
|
||||||
|
Ok(Self { syntax, src })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&self) -> Result<(), rinja_parser::ParseError> {
|
||||||
|
let Scenario { syntax, src } = self;
|
||||||
|
Ast::from_str(src, None, syntax)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Default)]
|
||||||
|
struct ArbitrarySyntax<'a>(Option<[Option<&'a str>; 6]>);
|
||||||
|
|
||||||
|
impl<'a> ArbitrarySyntax<'a> {
|
||||||
|
fn as_syntax(&self) -> Syntax<'a> {
|
||||||
|
let default = Syntax::default();
|
||||||
|
let values = self.0.unwrap_or_default();
|
||||||
|
Syntax {
|
||||||
|
block_start: values[0].unwrap_or(default.block_start),
|
||||||
|
block_end: values[1].unwrap_or(default.block_end),
|
||||||
|
expr_start: values[2].unwrap_or(default.expr_start),
|
||||||
|
expr_end: values[3].unwrap_or(default.expr_end),
|
||||||
|
comment_start: values[4].unwrap_or(default.comment_start),
|
||||||
|
comment_end: values[5].unwrap_or(default.comment_end),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
fuzz_parser/src/main.rs
Normal file
50
fuzz_parser/src/main.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use std::env::args_os;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use fuzz_parser::Scenario;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let mut args = args_os().fuse();
|
||||||
|
let exe = args.next().map(PathBuf::from);
|
||||||
|
let path = args.next().map(PathBuf::from);
|
||||||
|
let empty = args.next().map(|_| ());
|
||||||
|
|
||||||
|
let (Some(path), None) = (path, empty) else {
|
||||||
|
return Err(Error::Usage(exe));
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
match OpenOptions::new().read(true).open(Path::new(&path)) {
|
||||||
|
Ok(mut f) => {
|
||||||
|
f.read_to_end(&mut data)
|
||||||
|
.map_err(|err| Error::Read(err, path))?;
|
||||||
|
}
|
||||||
|
Err(err) => return Err(Error::Open(err, path)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let scenario = &Scenario::new(&data).map_err(Error::Build)?;
|
||||||
|
eprintln!("{scenario:#?}");
|
||||||
|
scenario.run().map_err(Error::Run)?;
|
||||||
|
println!("Success.");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, pretty_error_debug::Debug)]
|
||||||
|
enum Error {
|
||||||
|
#[error(
|
||||||
|
"wrong arguments supplied\nUsage: {} <path>",
|
||||||
|
.0.as_deref().unwrap_or(Path::new("fuzz_parser")).display(),
|
||||||
|
)]
|
||||||
|
Usage(Option<PathBuf>),
|
||||||
|
#[error("could not open input file {}", .1.display())]
|
||||||
|
Open(#[source] std::io::Error, PathBuf),
|
||||||
|
#[error("could not read opened input file {}", .1.display())]
|
||||||
|
Read(#[source] std::io::Error, PathBuf),
|
||||||
|
#[error("could not build scenario")]
|
||||||
|
Build(#[source] arbitrary::Error),
|
||||||
|
#[error("could not run scenario")]
|
||||||
|
Run(#[source] rinja_parser::ParseError),
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user