workflow: linear meta-prefix scan (the regex backtracked exponentially)

Review finding, measured: the leading-trivia prefix regex
(`^\s*(?:comment|comment|\s+)*export …`) partitions a whitespace run
ambiguously between its outer `\s*` and the starred `\s+` alternative,
so a script that ultimately FAILS the match backtracks exponentially —
~19 ms at 35 leading whitespace characters, ~174 ms at 38, ×2.2 per
character; a realistic near-miss (a comment header, blank indented
lines, then `const meta` missing its `export`) did not finish in 10
seconds. The regex ran on the HOST stack inside the synchronous
`start()`, where no vm timeout applies and no abort can interleave — a
benign one-token typo, exactly what SCRIPT_PARSE exists to bounce back
to the model, hung the whole process instead of reaching that designed
recovery.

Replaced with a hand-rolled linear trivia scan (whitespace + `//` and
`/* */` comments — the module already scans characters for the literal)
followed by an anchored `^export\s+const\s+meta\s*=\s*` on the
remainder, whose quantifiers cannot backtrack ambiguously. An
unterminated block comment before the statement now gets its own
SCRIPT_PARSE message. Regressions: the near-miss shape must reject in
under a second (the old regex would trip the suite timeout), plus the
unterminated-leading-comment and comment-to-EOF edges.
This commit is contained in:
Tianyi Cui
2026-07-06 00:51:04 +08:00
parent 2accf85714
commit ed3972a9c6
2 changed files with 62 additions and 4 deletions

View File

@@ -81,6 +81,27 @@ return 2`
expect(bad('export const meta = [1]').code).toBe('SCRIPT_PARSE')
})
it('a near-miss prefix (comment header + whitespace, then no `export`) fails FAST as SCRIPT_PARSE', () => {
// Regression: the previous all-alternation prefix regex backtracked
// exponentially on exactly this shape (~×2 per extra whitespace char once
// the match fails), spinning the host synchronously inside start(). The
// linear trivia scan must reject it in effectively zero time.
const nearMiss = `// deep-audit workflow: reviews every route handler\n${' \n'.repeat(40)}/* second header block */\n${' '.repeat(200)}\nconst meta = { name: 'x', description: 'y' }\n`
const started = Date.now()
expect(bad(nearMiss).code).toBe('SCRIPT_PARSE')
expect(Date.now() - started).toBeLessThan(1000)
})
it('an unterminated block comment BEFORE the meta statement is SCRIPT_PARSE', () => {
const error = bad('/* never closed\nexport const meta = { name: "x", description: "y" }')
expect(error.code).toBe('SCRIPT_PARSE')
expect(error.message).toContain('unterminated comment')
})
it('a line comment running to EOF leaves no meta statement (SCRIPT_PARSE)', () => {
expect(bad('// only a comment, no newline').code).toBe('SCRIPT_PARSE')
})
it('rejects template interpolation in the meta block as impure (SCRIPT_PARSE)', () => {
const error = bad('export const meta = { name: `w-${1}`, description: "d" }\nreturn 1')
expect(error.code).toBe('SCRIPT_PARSE')