Repository: raphlinus/pulldown-cmark (rust)

Issue:
[fuzz result]: link reference destination isn't fully checked for balanced parens
Link reference definitions are defined as:

> A link reference definition consists of a link label, optionally preceded by up to three spaces of indentation, followed by a colon (:), optional spaces or tabs (including up to one line ending), a **link destination**, optional spaces or tabs (including up to one line ending), and an optional link title, which if it is present must be separated from the link destination by spaces or tabs. No further character may occur.

And it defines a link destination as:

> a nonempty sequence of characters that does not start with <, does not include ASCII control characters or space character, and includes parentheses only if (a) they are backslash-escaped or (b) **they are part of a balanced pair of unescaped parentheses**. (Implementations may impose limits on parentheses nesting to avoid performance issues, but at least three levels of nesting should be supported.)

Events from pulldown-cmark:

```rust
"[~]:(\n" -> [
]
```

Events from pandoc:

```rust
"[~]:(\n" -> [
  Start(Paragraph)
    Text(Boxed("[~]:("))
  End(Paragraph)
]
```

Events from commonmark.js:

```rust
"[~]:(\n" -> [
  Start(Paragraph)
    Text(Boxed("[~]:("))
  End(Paragraph)
]
```

AST from [pandoc](https://pandoc.org/try/?params=%7B%22text%22%3A%22%5B~%5D%3A%28%5Cn%22%2C%22to%22%3A%22json%22%2C%22from%22%3A%22commonmark%22%7D)

```text
Pandoc {
    meta: {},
    blocks: [
        Para(
            [
                Str(
                    "[~]:(",
                ),
            ],
        ),
    ],
}
```


Pull request:
Check that parens in link def are nested
Fixes #737

Patch:
diff --git a/specs/regression.txt b/specs/regression.txt
index ab30536..6c77577 100644
--- a/specs/regression.txt
+++ b/specs/regression.txt
@@ -1454,3 +1454,14 @@ Table
 </tbody>
 </table>
 ````````````````````````````````
+
+ISSUE 737
+
+```````````````````````````````` example
+[x] is not a valid link definition, because parens aren't balanced.
+
+[x]: (
+.
+<p>[x] is not a valid link definition, because parens aren't balanced.</p>
+<p>[x]: (</p>
+````````````````````````````````
diff --git a/src/scanners.rs b/src/scanners.rs
index 01f51c1..34b543e 100644
--- a/src/scanners.rs
+++ b/src/scanners.rs
@@ -921,6 +921,9 @@ pub(crate) fn scan_link_dest(
             }
             i += 1;
         }
+        if nest != 0 {
+            return None;
+        }
         Some((i, &data[start_ix..(start_ix + i)]))
     }
 }


Test patch:
diff --git a/tests/suite/regression.rs b/tests/suite/regression.rs
index 0979e74..40d4f17 100644
--- a/tests/suite/regression.rs
+++ b/tests/suite/regression.rs
@@ -1649,7 +1649,7 @@ fn regression_test_111() {
 "##;
     let expected = r##"<p>j*<em><em>5</em>=</em></p>
 "##;
-  
+
     test_markdown_html(original, expected, false, false, false);
 }
 
@@ -1718,3 +1718,16 @@ Table
 
     test_markdown_html(original, expected, false, false, false);
 }
+
+#[test]
+fn regression_test_113() {
+    let original = r##"[x] is not a valid link definition, because parens aren't balanced.
+
+[x]: (
+"##;
+    let expected = r##"<p>[x] is not a valid link definition, because parens aren't balanced.</p>
+<p>[x]: (</p>
+"##;
+
+    test_markdown_html(original, expected, false, false, false);
+}