fix(parser): bound folding depth and macro expansion work
Assisted-by: GLM 5.3
This commit is contained in:
+29
-18
@@ -16,12 +16,21 @@ import (
|
||||
"sourcedock.dev/petrbalvin/gasm-sdk/token"
|
||||
)
|
||||
|
||||
// maxFoldDepth bounds the nesting the folder follows, counting parenthesis
|
||||
// groups and unary signs alike. Real expressions nest a handful deep, and
|
||||
// beyond the bound the expression simply fails to fold, which lands it in
|
||||
// the ordinary operand paths. Without a bound, a hostile file parks the
|
||||
// folder millions of frames down the mutual recursion of foldAdd, foldMul
|
||||
// and foldFactor, and the goroutine stack overflows with a fatal error no
|
||||
// caller can recover from.
|
||||
const maxFoldDepth = 1000
|
||||
|
||||
// foldExpr evaluates the constant integer expression at the head of ts and
|
||||
// returns its value together with the unconsumed tokens. ok is false when
|
||||
// the tokens do not form an expression, which is the callers' signal to use
|
||||
// the ordinary parsing paths.
|
||||
func foldExpr(ts []token.Token) (val int64, rest []token.Token, ok bool) {
|
||||
v, rest, ok := foldAdd(ts)
|
||||
v, rest, ok := foldAdd(ts, 0)
|
||||
if !ok {
|
||||
return 0, ts, false
|
||||
}
|
||||
@@ -30,8 +39,8 @@ func foldExpr(ts []token.Token) (val int64, rest []token.Token, ok bool) {
|
||||
|
||||
// foldAdd parses addition-level expressions: +, - and | bind loosest, the
|
||||
// Plan 9 convention that makes x<<1|3 read as (x<<1)|3.
|
||||
func foldAdd(ts []token.Token) (int64, []token.Token, bool) {
|
||||
v, rest, ok := foldMul(ts)
|
||||
func foldAdd(ts []token.Token, depth int) (int64, []token.Token, bool) {
|
||||
v, rest, ok := foldMul(ts, depth)
|
||||
if !ok {
|
||||
return 0, ts, false
|
||||
}
|
||||
@@ -40,7 +49,7 @@ func foldAdd(ts []token.Token) (int64, []token.Token, bool) {
|
||||
if kind != token.Plus && kind != token.Minus && kind != token.Pipe {
|
||||
return v, rest, true
|
||||
}
|
||||
w, r2, ok := foldMul(rest[1:])
|
||||
w, r2, ok := foldMul(rest[1:], depth)
|
||||
if !ok {
|
||||
return v, rest, true
|
||||
}
|
||||
@@ -59,43 +68,43 @@ func foldAdd(ts []token.Token) (int64, []token.Token, bool) {
|
||||
|
||||
// foldMul parses multiplication-level expressions: *, / and the bit
|
||||
// operators &, << and >>.
|
||||
func foldMul(ts []token.Token) (int64, []token.Token, bool) {
|
||||
v, rest, ok := foldFactor(ts)
|
||||
func foldMul(ts []token.Token, depth int) (int64, []token.Token, bool) {
|
||||
v, rest, ok := foldFactor(ts, depth)
|
||||
if !ok {
|
||||
return 0, ts, false
|
||||
}
|
||||
for len(rest) > 0 {
|
||||
switch rest[0].Kind {
|
||||
case token.Star:
|
||||
w, r2, ok := foldFactor(rest[1:])
|
||||
w, r2, ok := foldFactor(rest[1:], depth)
|
||||
if !ok {
|
||||
return v, rest, true
|
||||
}
|
||||
v *= w
|
||||
rest = r2
|
||||
case token.Slash:
|
||||
w, r2, ok := foldFactor(rest[1:])
|
||||
w, r2, ok := foldFactor(rest[1:], depth)
|
||||
if !ok || w == 0 {
|
||||
return v, rest, true
|
||||
}
|
||||
v /= w
|
||||
rest = r2
|
||||
case token.Ampersand:
|
||||
w, r2, ok := foldFactor(rest[1:])
|
||||
w, r2, ok := foldFactor(rest[1:], depth)
|
||||
if !ok {
|
||||
return v, rest, true
|
||||
}
|
||||
v &= w
|
||||
rest = r2
|
||||
case token.LShift:
|
||||
w, r2, ok := foldFactor(rest[1:])
|
||||
w, r2, ok := foldFactor(rest[1:], depth)
|
||||
if !ok || w < 0 || w >= 64 {
|
||||
return v, rest, true
|
||||
}
|
||||
v <<= uint(w)
|
||||
rest = r2
|
||||
case token.RShift:
|
||||
w, r2, ok := foldFactor(rest[1:])
|
||||
w, r2, ok := foldFactor(rest[1:], depth)
|
||||
if !ok || w < 0 || w >= 64 {
|
||||
return v, rest, true
|
||||
}
|
||||
@@ -109,9 +118,11 @@ func foldMul(ts []token.Token) (int64, []token.Token, bool) {
|
||||
}
|
||||
|
||||
// foldFactor parses a number, a parenthesised expression, or a unary sign
|
||||
// or complement.
|
||||
func foldFactor(ts []token.Token) (int64, []token.Token, bool) {
|
||||
if len(ts) == 0 {
|
||||
// or complement. Each parenthesis group and each unary operator costs one
|
||||
// depth level, so nesting beyond maxFoldDepth fails here instead of growing
|
||||
// the stack without end.
|
||||
func foldFactor(ts []token.Token, depth int) (int64, []token.Token, bool) {
|
||||
if len(ts) == 0 || depth > maxFoldDepth {
|
||||
return 0, ts, false
|
||||
}
|
||||
switch ts[0].Kind {
|
||||
@@ -122,21 +133,21 @@ func foldFactor(ts []token.Token) (int64, []token.Token, bool) {
|
||||
}
|
||||
return v, ts[1:], true
|
||||
case token.LParen:
|
||||
v, rest, ok := foldAdd(ts[1:])
|
||||
v, rest, ok := foldAdd(ts[1:], depth+1)
|
||||
if !ok || len(rest) == 0 || rest[0].Kind != token.RParen {
|
||||
return 0, ts, false
|
||||
}
|
||||
return v, rest[1:], true
|
||||
case token.Minus:
|
||||
v, rest, ok := foldFactor(ts[1:])
|
||||
v, rest, ok := foldFactor(ts[1:], depth+1)
|
||||
if !ok {
|
||||
return 0, ts, false
|
||||
}
|
||||
return -v, rest, true
|
||||
case token.Plus:
|
||||
return foldFactor(ts[1:])
|
||||
return foldFactor(ts[1:], depth+1)
|
||||
case token.Tilde:
|
||||
v, rest, ok := foldFactor(ts[1:])
|
||||
v, rest, ok := foldFactor(ts[1:], depth+1)
|
||||
if !ok {
|
||||
return 0, ts, false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user