aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Bleecher Snyder <josharian@gmail.com>2019-01-01 12:22:42 -1000
committeralandonovan <adonovan@google.com>2019-01-01 17:22:42 -0500
commit70a4f43bd14540d466ebd8601bbcd358d47ef7af (patch)
treeb62c9e1dddb0e0c49d6bc404ebd98f047e9d9573
parent783d9fbf8af9196568fdcb7564efe31f41671e55 (diff)
downloadstarlark-go-70a4f43bd14540d466ebd8601bbcd358d47ef7af.tar.gz
resolve: check number of args (#82)
The compiler currently uses an encoding that limits calls to 255 positional and 255 keyword arguments. There's no graceful way to return an error during compilation. Check the number of args during resolution as well, when we can return an error gracefully.
-rw-r--r--internal/compile/compile.go3
-rw-r--r--resolve/resolve.go13
2 files changed, 15 insertions, 1 deletions
diff --git a/internal/compile/compile.go b/internal/compile/compile.go
index c184e64..300d196 100644
--- a/internal/compile/compile.go
+++ b/internal/compile/compile.go
@@ -1599,7 +1599,8 @@ func (fcomp *fcomp) args(call *syntax.CallExpr) (op Opcode, arg uint32) {
// TODO(adonovan): avoid this with a more flexible encoding.
if p >= 256 || n >= 256 {
- log.Fatalf("%s: compiler error: too many arguments in call", call.Lparen)
+ // resolve already checked this; should be unreachable
+ panic("too many arguments in call")
}
return CALL + Opcode(callmode), uint32(p<<8 | n)
diff --git a/resolve/resolve.go b/resolve/resolve.go
index 59c486a..9e21ee1 100644
--- a/resolve/resolve.go
+++ b/resolve/resolve.go
@@ -670,6 +670,7 @@ func (r *resolver) expr(e syntax.Expr) {
r.expr(e.Fn)
var seenVarargs, seenKwargs bool
var seenName map[string]bool
+ var n, p int
for _, arg := range e.Args {
pos, _ := arg.Span()
if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
@@ -690,6 +691,7 @@ func (r *resolver) expr(e syntax.Expr) {
r.expr(arg)
} else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ {
// k=v
+ n++
if seenKwargs {
r.errorf(pos, "argument may not follow **kwargs")
}
@@ -705,6 +707,7 @@ func (r *resolver) expr(e syntax.Expr) {
r.expr(binop.Y)
} else {
// positional argument
+ p++
if seenVarargs {
r.errorf(pos, "argument may not follow *args")
} else if seenKwargs {
@@ -716,6 +719,16 @@ func (r *resolver) expr(e syntax.Expr) {
}
}
+ // Fail gracefully if compiler-imposed limit is exceeded.
+ if p >= 256 {
+ pos, _ := e.Span()
+ r.errorf(pos, "%v positional arguments in call, limit is 255", p)
+ }
+ if n >= 256 {
+ pos, _ := e.Span()
+ r.errorf(pos, "%v keyword arguments in call, limit is 255", n)
+ }
+
case *syntax.LambdaExpr:
if !AllowLambda {
r.errorf(e.Lambda, doesnt+"support lambda")