Repository: raphlinus/pulldown-cmark (rust)

Issue:
Index out of bounds at `firstpass.rs:1424`
I tried running the existing `parse` fuzzer, and found this crash:

```
thread '<unnamed>' panicked at 'index out of bounds: the len is 14 but the index is 14', /home/mg/src/pulldown-cmark/src/firstpass.rs:1424:13
stack backtrace:
   0: rust_begin_unwind
             at /rustc/6bba061467f7c2cab04b262b95eb67bf89265587/library/std/src/panicking.rs:593:5
   1: core::panicking::panic_fmt
             at /rustc/6bba061467f7c2cab04b262b95eb67bf89265587/library/core/src/panicking.rs:67:14
   2: core::panicking::panic_bounds_check
             at /rustc/6bba061467f7c2cab04b262b95eb67bf89265587/library/core/src/panicking.rs:162:5
   3: core::option::Option<T>::map_or
   4: pulldown_cmark::firstpass::scan_paragraph_interrupt
   5: pulldown_cmark::firstpass::FirstPass::parse_paragraph
   6: pulldown_cmark::firstpass::FirstPass::parse_block
   7: pulldown_cmark::firstpass::FirstPass::run
   8: pulldown_cmark::firstpass::run_first_pass
   9: pulldown_cmark::parse::Parser::new_ext
```

The input is a file with a lot of null bytes: [minimized-from-e9832c8a219680362d96eba6a59a76ace4b3cd40.zip](https://github.com/raphlinus/pulldown-cmark/files/11779703/minimized-from-e9832c8a219680362d96eba6a59a76ace4b3cd40.zip).

```
Output of `std::fmt::Debug`:

	FuzzingInput {
	    markdown: ".\r> ^](\r\u{c}\r\0\0\r.\r[^\0\0\\\0\0\0^^^^^]",
	    tables: false,
	    footnotes: true,
	    strikethrough: false,
	    tasklists: true,
	    smart_punctuation: false,
	    heading_attributes: false,
	}
```


Pull request description:
Fix index out of bounds when parsing GFM footnote
The code here was introduced in #654 and the crash was found using

    cargo fuzz run parse

Fixes #666.

Patch:
diff --git a/src/firstpass.rs b/src/firstpass.rs
index 8754a78..091fd4d 100644
--- a/src/firstpass.rs
+++ b/src/firstpass.rs
@@ -1420,9 +1420,10 @@ fn scan_paragraph_interrupt(bytes: &[u8], current_container: bool, gfm_footnote:
         })
         || bytes.starts_with(b"<")
             && (get_html_end_tag(&bytes[1..]).is_some() || starts_html_block_type_6(&bytes[1..]))
-        || (gfm_footnote && bytes.starts_with(b"[^") && scan_link_label_rest(std::str::from_utf8(&bytes[2..]).unwrap(), &|_| None).map_or(false, |(len, _)| {
-            bytes[2 + len] == b':'
-        }))
+        || (gfm_footnote
+            && bytes.starts_with(b"[^")
+            && scan_link_label_rest(std::str::from_utf8(&bytes[2..]).unwrap(), &|_| None)
+                .map_or(false, |(len, _)| bytes.get(2 + len) == Some(&b':')))
 }
 
 /// Assumes `text_bytes` is preceded by `<`.


Test patch:
diff --git a/tests/errors.rs b/tests/errors.rs
index cac3479..b194bcb 100644
--- a/tests/errors.rs
+++ b/tests/errors.rs
@@ -85,6 +85,15 @@ fn test_fuzzer_input_12() {
     parse_all_options("\u{c}-\n\u{c}\n-");
 }
 
+#[test]
+fn test_fuzzer_input_13() {
+    // Does not fail with Options::all():
+    Parser::new_ext(
+        ".\r> ^](\r\u{c}\r\0\0\r.\r[^\0\0\\\0\0\0^^^^^]",
+        Options::ENABLE_FOOTNOTES,
+    );
+}
+
 #[test]
 fn test_wrong_code_block() {
     parse(