Skip to content

fix: Avoid O(n^2) backtracking in inline link href regex - #4013

Merged
UziTech merged 1 commit into
markedjs:masterfrom
hong4rc:perf/linear-link-regex
Jul 9, 2026
Merged

fix: Avoid O(n^2) backtracking in inline link href regex#4013
UziTech merged 1 commit into
markedjs:masterfrom
hong4rc:perf/linear-link-regex

Conversation

@hong4rc

@hong4rc hong4rc commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Marked version: current master (regex unchanged since 18.0.5)

Markdown flavor: n/a

Description

The inline link regex parses an unclosed link followed by a long whitespace run in O(n²) time. marked.parse('[](' + ' '.repeat(n)) is just text — an unclosed link — but with default options the parse time roughly quadruples each time the input doubles: n=16,000 → ~0.3 s, 32,000 → ~1.2 s, 64,000 → ~4.9 s, 125,000 → ~21 s.

The cause is the unquoted-href alternative [^ \t\n\x00-\x1f]* in src/rules.ts. Since it can match empty at any whitespace position, when there is no closing ) the leading \s*, the (empty) href, the optional title separator, and the trailing \s*\) all re-partition the same whitespace run at ~n positions, so the engine backtracks quadratically. #3902 hardened the title separator ([ \t]*[ \t]+|\n) against the same class of problem but left this zero-length href branch, so input that never reaches the title branch still backtracks.

The fix requires the unquoted-href branch to match at least one non-whitespace character (*+) and keeps the legitimate empty-href case [foo]() via a (?=\)) lookahead. CommonMark specifies that an unquoted link destination ends at whitespace, so requiring ≥1 non-whitespace character there is spec-correct. After the change the same input parses in linear time (64 KB → ~1 ms) and ordinary links are unaffected: the full spec and unit suites stay green (test:specs 1749/0, test:unit 188/0), and I added test/specs/redos/quadratic_link_empty_href.cjs next to the existing quadratic guards so any regression fails fast.

Contributor

  • Test(s) exist to ensure functionality and minimize regression: test/specs/redos/quadratic_link_empty_href.cjs.
  • If submitting new feature, it has been documented in the appropriate places.
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

@hong4rc is attempting to deploy a commit to the MarkedJS Team on Vercel.

A member of the Team first needs to authorize it.

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marked-website Ready Ready Preview, Comment Jul 9, 2026 3:17pm

Request Review

@UziTech UziTech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 💯

@UziTech
UziTech merged commit a009808 into markedjs:master Jul 9, 2026
8 checks passed
github-actions Bot pushed a commit that referenced this pull request Jul 9, 2026
## [18.0.6](v18.0.5...v18.0.6) (2026-07-09)

### Bug Fixes

* Avoid O(n^2) backtracking in inline link href regex ([#4013](#4013)) ([a009808](a009808))
* Fix ordered lists after blockquotes ([#4003](#4003)) ([33928d0](33928d0))
* keep trailing text on HTML block close line for PI, declarations, and CDATA ([#3991](#3991)) ([bbb84c8](bbb84c8))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants