Repository navigation
Commit 0f0a860
Fix quadratic-time backtracking in hash header regex
`HashHeaderProcessor.RE` matches the header text lazily one character at
a time and, after each step, tries `#*(?:\n|$)` to see whether only
closing hashes remain. When the lazy match is inside a run of `#` that
is followed by more text, that check scans to the end of the run and
then fails, so a run of n hashes costs O(n^2). A line such as `# `
followed by 8000 `#` and an `x` takes about 13 seconds to convert. A
run of hashes ending in a backslash (`'#' * n + '\\'`) hits the same path.
Header text now consumes a run of hashes in one step when the run is
followed by something other than a newline or the end of the block, and
a lone `#` is no longer matched by the single-character branch. The
lazy match therefore only stops at the start of a hash run, never
inside one, and every match and capture group is unchanged. This was
checked against the old pattern on every string of up to 8 characters
over `#`, `\`, `a` and newline, plus random longer strings.
This differs from #1545, where the time was spent in inline escape
handling; here the time is spent inside the block regex itself.1 parent 5e335ef commit 0f0a860
3 files changed
Lines changed: 15 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
458 | 458 | | |
459 | 459 | | |
460 | 460 | | |
461 | | - | |
| 461 | + | |
462 | 462 | | |
463 | 463 | | |
464 | 464 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
779 | 779 | | |
780 | 780 | | |
781 | 781 | | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
0 commit comments