Skip to content

Commit 8a47812

Browse files
committed
Convert stack overflow errors to SyntaxError instances
Issue #1254
1 parent 3bc83f9 commit 8a47812

5 files changed

Lines changed: 33 additions & 11 deletions

File tree

acorn-loose/src/state.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,14 @@ export class LooseParser {
154154

155155
parse() {
156156
this.next()
157-
return this.parseTopLevel()
157+
try {
158+
return this.parseTopLevel()
159+
} catch (e) {
160+
if (e instanceof Error && (/\bstack\b.*\b(exceeded|overflow)\b/i.test(e.message) || /\btoo much recursion\b/i.test(e.message)))
161+
this.toks.raise(this.toks.start, "Not enough stack space to parse input")
162+
else
163+
throw e
164+
}
158165
}
159166

160167
static extend(...plugins) {

acorn/src/expression.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,17 @@ pp.checkPropClash = function(prop, propHash, refDestructuringErrors) {
9494
// delayed syntax error at correct position).
9595

9696
pp.parseExpression = function(forInit, refDestructuringErrors) {
97-
let startPos = this.start, startLoc = this.startLoc
98-
let expr = this.parseMaybeAssign(forInit, refDestructuringErrors)
99-
if (this.type === tt.comma) {
100-
let node = this.startNodeAt(startPos, startLoc)
101-
node.expressions = [expr]
102-
while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(forInit, refDestructuringErrors))
103-
return this.finishNode(node, "SequenceExpression")
104-
}
105-
return expr
97+
return this.catchStackOverflow(() => {
98+
let startPos = this.start, startLoc = this.startLoc
99+
let expr = this.parseMaybeAssign(forInit, refDestructuringErrors)
100+
if (this.type === tt.comma) {
101+
let node = this.startNodeAt(startPos, startLoc)
102+
node.expressions = [expr]
103+
while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(forInit, refDestructuringErrors))
104+
return this.finishNode(node, "SequenceExpression")
105+
}
106+
return expr
107+
})
106108
}
107109

108110
// Parse an assignment expression. This includes applications of

acorn/src/parseutil.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ pp.eatContextual = function(name) {
5959
return true
6060
}
6161

62+
pp.catchStackOverflow = function(f) {
63+
try {
64+
return f()
65+
} catch (e) {
66+
if (e instanceof Error && (/\bstack\b.*\b(exceeded|overflow)\b/i.test(e.message) || /\btoo much recursion\b/i.test(e.message)))
67+
this.raise(this.start, "Not enough stack space to parse input")
68+
else
69+
throw e
70+
}
71+
}
72+
6273
// Asserts that following token is given contextual keyword.
6374

6475
pp.expectContextual = function(name) {

acorn/src/state.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export class Parser {
102102
parse() {
103103
let node = this.options.program || this.startNode()
104104
this.nextToken()
105-
return this.parseTopLevel(node)
105+
return this.catchStackOverflow(() => this.parseTopLevel(node))
106106
}
107107

108108
get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }

test/tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29968,3 +29968,5 @@ test("foo.if() / 2", {
2996829968
})
2996929969

2997029970
test("({a: /=/})", {}, {ecmaVersion: 5})
29971+
29972+
testFail("[".repeat(2000) + "1" + "]".repeat(2000), "~Not enough stack space", {ecmaVersion: "latest"})

0 commit comments

Comments
 (0)