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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants