Panic when parsing fuzzed file with malformed HTML in it · Issue #521 · pulldown-cmark/pulldown-cmark

There's already the support for fuzzing here, but I found this issue through https://github.com/rust-fuzz/targets and wrote a simple cargo-fuzz fuzzing target that only checks that parsing arbitrary HTML doesn't panic. (Might be worth having a cargo-fuzz target in addition to the existing one, simply because cargo fuzz is easier to get set up and seems to be able to run test cases faster? Though I know testing for panics isn't the main purpose of the existing fuzzer)

#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &str| {
    let mut output = String::new();
    let parser = pulldown_cmark::Parser::new(data);
    pulldown_cmark::html::push_html(&mut output, parser);
});

Below's a standalone demo program. I tested that it crashes both with 0.8.0 from crates.io, as well as the latest version from git (d99667b, if just going to the directory in ~/.cargo/git/checkouts is correct).

fn main() {
    let mut output = String::new();
    let parser = pulldown_cmark::Parser::new(">\n >>><N\n");
    pulldown_cmark::html::push_html(&mut output, parser);
}

Backtrace is below

thread 'main' panicked at 'range start index 4 out of range for slice of length 3', /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/scanners.rs:1061:45
stack backtrace:
   0: rust_begin_unwind
             at /rustc/61edfd591cedff66fca639c02f66984f6271e5a6/library/std/src/panicking.rs:493:5
   1: core::panicking::panic_fmt
             at /rustc/61edfd591cedff66fca639c02f66984f6271e5a6/library/core/src/panicking.rs:92:14
   2: core::slice::index::slice_start_index_len_fail
             at /rustc/61edfd591cedff66fca639c02f66984f6271e5a6/library/core/src/slice/index.rs:34:5
   3: <core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index
             at /home/jess/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/index.rs:322:13
   4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
             at /home/jess/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/index.rs:15:9
   5: pulldown_cmark::scanners::scan_html_block_inner
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/scanners.rs:1061:45
   6: pulldown_cmark::parse::Parser::scan_inline_html
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/parse.rs:841:29
   7: pulldown_cmark::parse::Parser::handle_inline_pass1::{{closure}}
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/parse.rs:243:29
   8: core::option::Option<T>::and_then
             at /home/jess/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:724:24
   9: pulldown_cmark::parse::Parser::handle_inline_pass1
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/parse.rs:242:43
  10: pulldown_cmark::parse::Parser::handle_inline
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/parse.rs:196:9
  11: <pulldown_cmark::parse::Parser as core::iter::traits::iterator::Iterator>::next
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/parse.rs:1453:21
  12: pulldown_cmark::html::HtmlWriter<I,W>::run
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/html.rs:87:33
  13: pulldown_cmark::html::push_html
             at /home/jess/.cargo/git/checkouts/pulldown-cmark-0e08cefe6e291038/d99667b/src/html.rs:419:5
  14: scratchNTsHONsYl::main
             at ./main.rs:4:5
  15: core::ops::function::FnOnce::call_once
             at /home/jess/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.