PR #35 Check event balance when fuzzing

Merge branch 'balance'
This commit is contained in:
Noah Hellman 2023-04-10 18:58:44 +02:00
commit 176d026cbb
7 changed files with 67 additions and 10 deletions

View file

@ -68,6 +68,12 @@ jobs:
run: make lint run: make lint
fuzz: fuzz:
name: Fuzz name: Fuzz
strategy:
matrix:
target:
- parse
- parse_balance
- html
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: "Checkout" - name: "Checkout"
@ -77,13 +83,10 @@ jobs:
rustup update nightly rustup update nightly
rustup default nightly rustup default nightly
cargo install afl cargo install afl
- name: "Fuzz parser" - name: "Fuzz"
run: | run: |
echo core | sudo tee /proc/sys/kernel/core_pattern echo core | sudo tee /proc/sys/kernel/core_pattern
AFL_TARGET=parse make afl_quick AFL_TARGET=${{ matrix.target }} make afl_quick
- name: "Fuzz html"
run: |
AFL_TARGET=html make afl_quick
bench: bench:
name: Benchmark name: Benchmark
runs-on: ubuntu-latest runs-on: ubuntu-latest

View file

@ -557,8 +557,9 @@ impl<'s> Parser<'s> {
self.input.span = self.input.span.after(len); self.input.span = self.input.span.after(len);
self.push(EventKind::Enter(Autolink)); self.push(EventKind::Enter(Autolink));
self.push(EventKind::Str); self.push(EventKind::Str);
self.push(EventKind::Exit(Autolink));
self.input.span = self.input.span.after(1); self.input.span = self.input.span.after(1);
return self.push(EventKind::Exit(Autolink)); return Some(Continue);
} }
} }
None None
@ -1507,22 +1508,22 @@ mod test {
"<https://example.com>", "<https://example.com>",
(Enter(Autolink), "https://example.com"), (Enter(Autolink), "https://example.com"),
(Str, "https://example.com"), (Str, "https://example.com"),
(Exit(Autolink), ">") (Exit(Autolink), "https://example.com")
); );
test_parse!( test_parse!(
"<a@b.c>", "<a@b.c>",
(Enter(Autolink), "a@b.c"), (Enter(Autolink), "a@b.c"),
(Str, "a@b.c"), (Str, "a@b.c"),
(Exit(Autolink), ">"), (Exit(Autolink), "a@b.c"),
); );
test_parse!( test_parse!(
"<http://a.b><http://c.d>", "<http://a.b><http://c.d>",
(Enter(Autolink), "http://a.b"), (Enter(Autolink), "http://a.b"),
(Str, "http://a.b"), (Str, "http://a.b"),
(Exit(Autolink), ">"), (Exit(Autolink), "http://a.b"),
(Enter(Autolink), "http://c.d"), (Enter(Autolink), "http://c.d"),
(Str, "http://c.d"), (Str, "http://c.d"),
(Exit(Autolink), ">") (Exit(Autolink), "http://c.d"),
); );
test_parse!("<not-a-url>", (Str, "<not-a-url>")); test_parse!("<not-a-url>", (Str, "<not-a-url>"));
} }

View file

@ -1540,6 +1540,36 @@ mod test {
); );
} }
#[test]
fn autolink() {
test_parse!(
"<proto:url>\n",
Start(Paragraph, Attributes::new()),
Start(
Link("proto:url".into(), LinkType::AutoLink),
Attributes::new()
),
Str("proto:url".into()),
End(Link("proto:url".into(), LinkType::AutoLink)),
End(Paragraph),
);
}
#[test]
fn email() {
test_parse!(
"<name@domain>\n",
Start(Paragraph, Attributes::new()),
Start(
Link("name@domain".into(), LinkType::Email),
Attributes::new()
),
Str("name@domain".into()),
End(Link("name@domain".into(), LinkType::Email)),
End(Paragraph),
);
}
#[test] #[test]
fn footnote_references() { fn footnote_references() {
test_parse!( test_parse!(

View file

@ -17,6 +17,10 @@ path = "src/main.rs"
name = "parse" name = "parse"
path = "src/parse.rs" path = "src/parse.rs"
[[bin]]
name = "parse_balance"
path = "src/parse_balance.rs"
[[bin]] [[bin]]
name = "html" name = "html"
path = "src/html.rs" path = "src/html.rs"

View file

@ -11,6 +11,21 @@ pub fn parse(data: &[u8]) {
} }
} }
/// Ensure containers are always balanced, i.e. opened and closed in correct order.
pub fn parse_balance(data: &[u8]) {
if let Ok(s) = std::str::from_utf8(data) {
let mut open = Vec::new();
for event in jotdown::Parser::new(s) {
match event {
jotdown::Event::Start(c, ..) => open.push(c.clone()),
jotdown::Event::End(c) => assert_eq!(open.pop().unwrap(), c),
_ => {}
}
}
assert_eq!(open, &[]);
}
}
pub fn html(data: &[u8]) { pub fn html(data: &[u8]) {
if data.iter().any(|i| *i == 0) { if data.iter().any(|i| *i == 0) {
return; return;

View file

@ -8,6 +8,7 @@ fn main() {
let f = match target.as_str() { let f = match target.as_str() {
"parse" => jotdown_afl::parse, "parse" => jotdown_afl::parse,
"parse_balance" => jotdown_afl::parse_balance,
"html" => jotdown_afl::html, "html" => jotdown_afl::html,
_ => panic!("unknown target '{}'", target), _ => panic!("unknown target '{}'", target),
}; };

View file

@ -0,0 +1,3 @@
fn main() {
afl::fuzz!(|data: &[u8]| { jotdown_afl::parse_balance(data) });
}