From be27472a8169dda7875330939f8115ab677cdc07 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Wed, 3 Apr 2019 15:08:57 -0700 Subject: [PATCH] Improve worst-case performance of inline.text regex The old regex may take quadratic time to scan for potential line breaks or email addresses starting at every point. Fix it to avoid scanning from points that would have been in the middle of a previous scan. Signed-off-by: Anders Kaseorg --- lib/marked.js | 9 +++------ test/redos/quadratic_br.js | 4 ++++ test/redos/quadratic_email.js | 4 ++++ test/specs/gfm/gfm.0.28.json | 3 +-- test/specs/redos-spec.js | 24 ++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 test/redos/quadratic_br.js create mode 100644 test/redos/quadratic_email.js create mode 100644 test/specs/redos-spec.js diff --git a/lib/marked.js b/lib/marked.js index 9d7c1555f3..39c25f2610 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -546,7 +546,7 @@ var inline = { code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/, br: /^( {2,}|\\)\n(?!\s*$)/, del: noop, - text: /^(`+|[^`])[\s\S]*?(?=[\\a${' '.repeat(50000)}

` +}; diff --git a/test/redos/quadratic_email.js b/test/redos/quadratic_email.js new file mode 100644 index 0000000000..08243fe5fa --- /dev/null +++ b/test/redos/quadratic_email.js @@ -0,0 +1,4 @@ +module.exports = { + markdown: 'a'.repeat(50000), + html: `

${'a'.repeat(50000)}

` +}; diff --git a/test/specs/gfm/gfm.0.28.json b/test/specs/gfm/gfm.0.28.json index f9c28eb2ab..75bffc64ce 100644 --- a/test/specs/gfm/gfm.0.28.json +++ b/test/specs/gfm/gfm.0.28.json @@ -141,8 +141,7 @@ "section": "Autolinks", "html": "

a.b-c_d@a.b

\n

a.b-c_d@a.b.

\n

a.b-c_d@a.b-

\n

a.b-c_d@a.b_

", "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_", - "example": 607, - "shouldFail": true + "example": 607 }, { "section": "Disallowed Raw HTML", diff --git a/test/specs/redos-spec.js b/test/specs/redos-spec.js new file mode 100644 index 0000000000..1f94a42e99 --- /dev/null +++ b/test/specs/redos-spec.js @@ -0,0 +1,24 @@ +const path = require('path'); +const fs = require('fs'); + +const redosDir = path.resolve(__dirname, '../redos'); + +describe('ReDOS tests', () => { + const files = fs.readdirSync(redosDir); + files.forEach(file => { + if (!file.match(/\.js$/)) { + return; + } + + it(file, () => { + const spec = require(path.resolve(redosDir, file)); + const before = process.hrtime(); + expect(spec).toRender(spec.html); + const elapsed = process.hrtime(before); + if (elapsed[0] > 0) { + const s = (elapsed[0] + elapsed[1] * 1e-9).toFixed(3); + fail(`took too long: ${s}s`); + } + }); + }); +});