mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-27 13:00:57 +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>
|
||||
```
|
||||
|
||||
`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.
|
||||
Or until it finds a panic.
|
||||
|
@ -9,11 +9,13 @@ publish = false
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
rinja = { path = "../../rinja" }
|
||||
rinja_parser = { path = "../../rinja_parser" }
|
||||
|
||||
arbitrary = { version = "1.3.2", features = ["derive"] }
|
||||
html-escape = "0.2.13"
|
||||
libfuzzer-sys = "0.4.7"
|
||||
thiserror = "1.0.63"
|
||||
|
||||
[[bin]]
|
||||
name = "all"
|
||||
@ -21,6 +23,12 @@ path = "fuzz_targets/all.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "filters"
|
||||
path = "fuzz_targets/filters.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "html"
|
||||
path = "fuzz_targets/html.rs"
|
||||
|
@ -1,9 +1,5 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz::Scenario;
|
||||
|
||||
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||
if let Ok(scenario) = fuzz::all::Scenario::new(data) {
|
||||
let _ = scenario.run();
|
||||
}
|
||||
let _ = <fuzz::all::Scenario as fuzz::Scenario>::fuzz(data);
|
||||
});
|
||||
|
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]
|
||||
|
||||
use fuzz::Scenario;
|
||||
|
||||
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||
if let Ok(scenario) = fuzz::html::Scenario::new(data) {
|
||||
let _ = scenario.run();
|
||||
}
|
||||
let _ = <fuzz::html::Scenario as fuzz::Scenario>::fuzz(data);
|
||||
});
|
||||
|
@ -1,9 +1,5 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz::Scenario;
|
||||
|
||||
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
|
||||
if let Ok(scenario) = fuzz::parser::Scenario::new(data) {
|
||||
let _ = scenario.run();
|
||||
}
|
||||
let _ = <fuzz::parser::Scenario as fuzz::Scenario>::fuzz(data);
|
||||
});
|
||||
|
@ -65,6 +65,7 @@ macro_rules! this_file {
|
||||
}
|
||||
|
||||
this_file! {
|
||||
crate::filters::Filters;
|
||||
crate::html::Html;
|
||||
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 filters;
|
||||
pub mod html;
|
||||
pub mod parser;
|
||||
|
||||
@ -7,6 +8,9 @@ use std::fmt;
|
||||
|
||||
pub const TARGETS: &[(&str, TargetBuilder)] = &[
|
||||
("all", |data| NamedTarget::new::<all::Scenario>(data)),
|
||||
("filters", |data| {
|
||||
NamedTarget::new::<filters::Scenario>(data)
|
||||
}),
|
||||
("html", |data| NamedTarget::new::<html::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 {
|
||||
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 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)]
|
||||
pub struct DisplayTargets;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user