mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +00:00
fuzz: fuzz text filters
This commit is contained in:
parent
1176c654ba
commit
33e80a2be4
@ -13,7 +13,7 @@ Then execute in this folder:
|
|||||||
RUST_BACKTRACE=1 nice cargo +nightly fuzz run <fuzz_target>
|
RUST_BACKTRACE=1 nice cargo +nightly fuzz run <fuzz_target>
|
||||||
```
|
```
|
||||||
|
|
||||||
`fuzz_target` is one out of `all`, `html` or `parser`.
|
`fuzz_target` is one out of `all`, `filters`, `html` or `parser`.
|
||||||
|
|
||||||
The execution won't stop, but continue until you kill it with ctrl+c.
|
The execution won't stop, but continue until you kill it with ctrl+c.
|
||||||
Or until it finds a panic.
|
Or until it finds a panic.
|
||||||
|
@ -9,11 +9,13 @@ publish = false
|
|||||||
cargo-fuzz = true
|
cargo-fuzz = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rinja = { path = "../../rinja" }
|
||||||
rinja_parser = { path = "../../rinja_parser" }
|
rinja_parser = { path = "../../rinja_parser" }
|
||||||
|
|
||||||
arbitrary = { version = "1.3.2", features = ["derive"] }
|
arbitrary = { version = "1.3.2", features = ["derive"] }
|
||||||
html-escape = "0.2.13"
|
html-escape = "0.2.13"
|
||||||
libfuzzer-sys = "0.4.7"
|
libfuzzer-sys = "0.4.7"
|
||||||
|
thiserror = "1.0.63"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "all"
|
name = "all"
|
||||||
@ -21,6 +23,12 @@ path = "fuzz_targets/all.rs"
|
|||||||
test = false
|
test = false
|
||||||
doc = false
|
doc = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "filters"
|
||||||
|
path = "fuzz_targets/filters.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "html"
|
name = "html"
|
||||||
path = "fuzz_targets/html.rs"
|
path = "fuzz_targets/html.rs"
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use fuzz::Scenario;
|
|
||||||
|
|
||||||
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||||
if let Ok(scenario) = fuzz::all::Scenario::new(data) {
|
let _ = <fuzz::all::Scenario as fuzz::Scenario>::fuzz(data);
|
||||||
let _ = scenario.run();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
5
fuzzing/fuzz/fuzz_targets/filters.rs
Normal file
5
fuzzing/fuzz/fuzz_targets/filters.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||||
|
let _ = <fuzz::filters::Scenario as fuzz::Scenario>::fuzz(data);
|
||||||
|
});
|
@ -1,9 +1,5 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use fuzz::Scenario;
|
|
||||||
|
|
||||||
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||||
if let Ok(scenario) = fuzz::html::Scenario::new(data) {
|
let _ = <fuzz::html::Scenario as fuzz::Scenario>::fuzz(data);
|
||||||
let _ = scenario.run();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use fuzz::Scenario;
|
|
||||||
|
|
||||||
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||||
if let Ok(scenario) = fuzz::parser::Scenario::new(data) {
|
let _ = <fuzz::parser::Scenario as fuzz::Scenario>::fuzz(data);
|
||||||
let _ = scenario.run();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@ -65,6 +65,7 @@ macro_rules! this_file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this_file! {
|
this_file! {
|
||||||
|
crate::filters::Filters;
|
||||||
crate::html::Html;
|
crate::html::Html;
|
||||||
crate::parser::Parser;
|
crate::parser::Parser;
|
||||||
}
|
}
|
||||||
|
88
fuzzing/fuzz/src/filters.rs
Normal file
88
fuzzing/fuzz/src/filters.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use arbitrary::{Arbitrary, Unstructured};
|
||||||
|
use rinja::filters;
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Debug, Clone, Copy)]
|
||||||
|
pub enum Scenario<'a> {
|
||||||
|
Text(Text<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> super::Scenario<'a> for Scenario<'a> {
|
||||||
|
type RunError = rinja::Error;
|
||||||
|
|
||||||
|
fn new(data: &'a [u8]) -> Result<Self, arbitrary::Error> {
|
||||||
|
Self::arbitrary_take_rest(Unstructured::new(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self) -> Result<(), Self::RunError> {
|
||||||
|
match *self {
|
||||||
|
Self::Text(text) => run_text(text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_text(filter: Text<'_>) -> Result<(), rinja::Error> {
|
||||||
|
let Text { input, filter } = filter;
|
||||||
|
let _ = match filter {
|
||||||
|
TextFilter::Capitalize => filters::capitalize(input)?.to_string(),
|
||||||
|
TextFilter::Center(a) => filters::center(input, a)?.to_string(),
|
||||||
|
TextFilter::Indent(a) => filters::indent(input, a)?.to_string(),
|
||||||
|
TextFilter::Linebreaks => filters::linebreaks(input)?.to_string(),
|
||||||
|
TextFilter::LinebreaksBr => filters::linebreaksbr(input)?.to_string(),
|
||||||
|
TextFilter::Lowercase => filters::lowercase(input)?.to_string(),
|
||||||
|
TextFilter::ParagraphBreaks => filters::paragraphbreaks(input)?.to_string(),
|
||||||
|
TextFilter::Safe(e) => match e {
|
||||||
|
Escaper::Html => filters::safe(input, filters::Html)?.to_string(),
|
||||||
|
Escaper::Text => filters::safe(input, filters::Text)?.to_string(),
|
||||||
|
},
|
||||||
|
TextFilter::Title => filters::title(input)?.to_string(),
|
||||||
|
TextFilter::Trim => filters::trim(input)?.to_string(),
|
||||||
|
TextFilter::Truncate(a) => filters::truncate(input, a)?.to_string(),
|
||||||
|
TextFilter::Uppercase => filters::uppercase(input)?.to_string(),
|
||||||
|
TextFilter::Urlencode => filters::urlencode(input)?.to_string(),
|
||||||
|
TextFilter::UrlencodeStrict => filters::urlencode_strict(input)?.to_string(),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Debug, Clone, Copy)]
|
||||||
|
pub struct Text<'a> {
|
||||||
|
input: &'a str,
|
||||||
|
filter: TextFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Debug, Clone, Copy)]
|
||||||
|
enum TextFilter {
|
||||||
|
Capitalize,
|
||||||
|
Center(usize),
|
||||||
|
Indent(usize),
|
||||||
|
Linebreaks,
|
||||||
|
LinebreaksBr,
|
||||||
|
Lowercase,
|
||||||
|
ParagraphBreaks,
|
||||||
|
Safe(Escaper),
|
||||||
|
Title,
|
||||||
|
Trim,
|
||||||
|
Truncate(usize),
|
||||||
|
Uppercase,
|
||||||
|
Urlencode,
|
||||||
|
UrlencodeStrict,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Debug, Clone, Copy)]
|
||||||
|
enum Escaper {
|
||||||
|
Html,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// abs
|
||||||
|
// escape,
|
||||||
|
// filesizeformat
|
||||||
|
// fmt
|
||||||
|
// format
|
||||||
|
// into_f64
|
||||||
|
// into_isize
|
||||||
|
// join
|
||||||
|
// json
|
||||||
|
// json_pretty
|
||||||
|
// wordcount
|
@ -1,4 +1,5 @@
|
|||||||
pub mod all;
|
pub mod all;
|
||||||
|
pub mod filters;
|
||||||
pub mod html;
|
pub mod html;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
@ -7,6 +8,9 @@ use std::fmt;
|
|||||||
|
|
||||||
pub const TARGETS: &[(&str, TargetBuilder)] = &[
|
pub const TARGETS: &[(&str, TargetBuilder)] = &[
|
||||||
("all", |data| NamedTarget::new::<all::Scenario>(data)),
|
("all", |data| NamedTarget::new::<all::Scenario>(data)),
|
||||||
|
("filters", |data| {
|
||||||
|
NamedTarget::new::<filters::Scenario>(data)
|
||||||
|
}),
|
||||||
("html", |data| NamedTarget::new::<html::Scenario>(data)),
|
("html", |data| NamedTarget::new::<html::Scenario>(data)),
|
||||||
("parser", |data| NamedTarget::new::<parser::Scenario>(data)),
|
("parser", |data| NamedTarget::new::<parser::Scenario>(data)),
|
||||||
];
|
];
|
||||||
@ -16,10 +20,25 @@ pub type TargetBuilder = for<'a> fn(&'a [u8]) -> Result<NamedTarget<'a>, arbitra
|
|||||||
pub trait Scenario<'a>: fmt::Debug + Sized {
|
pub trait Scenario<'a>: fmt::Debug + Sized {
|
||||||
type RunError: Error + Send + 'static;
|
type RunError: Error + Send + 'static;
|
||||||
|
|
||||||
|
fn fuzz(data: &'a [u8]) -> Result<(), FuzzError<Self::RunError>> {
|
||||||
|
Self::new(data)
|
||||||
|
.map_err(FuzzError::New)?
|
||||||
|
.run()
|
||||||
|
.map_err(FuzzError::Run)
|
||||||
|
}
|
||||||
|
|
||||||
fn new(data: &'a [u8]) -> Result<Self, arbitrary::Error>;
|
fn new(data: &'a [u8]) -> Result<Self, arbitrary::Error>;
|
||||||
fn run(&self) -> Result<(), Self::RunError>;
|
fn run(&self) -> Result<(), Self::RunError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum FuzzError<RunError: Error + Send + 'static> {
|
||||||
|
#[error("could not build scenario")]
|
||||||
|
New(#[source] arbitrary::Error),
|
||||||
|
#[error("could not run scenario")]
|
||||||
|
Run(#[source] RunError),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct DisplayTargets;
|
pub struct DisplayTargets;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user