Skip to content

Commit b1ddd3c

Browse files
authoredApr 5, 2019
Merge pull request #1460 from andersk/inline-text-quadratic
Improve worst-case performance of inline.text regex
2 parents ba1de1e + be27472 commit b1ddd3c

File tree

5 files changed

+36
-8
lines changed

5 files changed

+36
-8
lines changed
 

‎lib/marked.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ var inline = {
546546
code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
547547
br: /^( {2,}|\\)\n(?!\s*$)/,
548548
del: noop,
549-
text: /^(`+|[^`])[\s\S]*?(?=[\\<!\[`*]|\b_| {2,}\n|$)/
549+
text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/
550550
};
551551

552552
// list of punctuation marks from common mark spec
@@ -615,10 +615,7 @@ inline.gfm = merge({}, inline.normal, {
615615
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
616616
_backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
617617
del: /^~+(?=\S)([\s\S]*?\S)~+/,
618-
text: edit(inline.text)
619-
.replace(']|', '~]|')
620-
.replace('|$', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|$')
621-
.getRegex()
618+
text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
622619
});
623620

624621
inline.gfm.url = edit(inline.gfm.url, 'i')
@@ -630,7 +627,7 @@ inline.gfm.url = edit(inline.gfm.url, 'i')
630627

631628
inline.breaks = merge({}, inline.gfm, {
632629
br: edit(inline.br).replace('{2,}', '*').getRegex(),
633-
text: edit(inline.gfm.text).replace('{2,}', '*').getRegex()
630+
text: edit(inline.gfm.text).replace(/\{2,\}/g, '*').getRegex()
634631
});
635632

636633
/**

‎test/redos/quadratic_br.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
markdown: `a${' '.repeat(50000)}`,
3+
html: `<p>a${' '.repeat(50000)}</p>`
4+
};

‎test/redos/quadratic_email.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
markdown: 'a'.repeat(50000),
3+
html: `<p>${'a'.repeat(50000)}</p>`
4+
};

‎test/specs/gfm/gfm.0.28.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,7 @@
141141
"section": "Autolinks",
142142
"html": "<p><a href=\"mailto:a.b-c_d@a.b\">a.b-c_d@a.b</a></p>\n<p><a href=\"mailto:a.b-c_d@a.b\">a.b-c_d@a.b</a>.</p>\n<p>a.b-c_d@a.b-</p>\n<p>a.b-c_d@a.b_</p>",
143143
"markdown": "a.b-c_d@a.b\n\na.b-c_d@a.b.\n\na.b-c_d@a.b-\n\na.b-c_d@a.b_",
144-
"example": 607,
145-
"shouldFail": true
144+
"example": 607
146145
},
147146
{
148147
"section": "Disallowed Raw HTML",

‎test/specs/redos-spec.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const path = require('path');
2+
const fs = require('fs');
3+
4+
const redosDir = path.resolve(__dirname, '../redos');
5+
6+
describe('ReDOS tests', () => {
7+
const files = fs.readdirSync(redosDir);
8+
files.forEach(file => {
9+
if (!file.match(/\.js$/)) {
10+
return;
11+
}
12+
13+
it(file, () => {
14+
const spec = require(path.resolve(redosDir, file));
15+
const before = process.hrtime();
16+
expect(spec).toRender(spec.html);
17+
const elapsed = process.hrtime(before);
18+
if (elapsed[0] > 0) {
19+
const s = (elapsed[0] + elapsed[1] * 1e-9).toFixed(3);
20+
fail(`took too long: ${s}s`);
21+
}
22+
});
23+
});
24+
});

0 commit comments

Comments
 (0)
Please sign in to comment.