summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-05-24 00:00:42 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-05-24 00:00:42 -0700
commit8c249e7aa60489b353658c934b0668a045d7fa0c (patch)
treeaede72783ea6714efeed6e1168265a0478592b7a /lib.c
parent0a9f9ae8d11a43108f0b8fffae954da4f9539b7f (diff)
downloadtxr-8c249e7aa60489b353658c934b0668a045d7fa0c.tar.gz
txr-8c249e7aa60489b353658c934b0668a045d7fa0c.tar.bz2
txr-8c249e7aa60489b353658c934b0668a045d7fa0c.zip
lib: fix issue uncovered by recent vm CALL insn change.
The functions funcall1 through funcall4, when invoking a VM function, are not defending against the case when there are more arguments than the function can take. As a result, some :mass-delegate tests in tests/012/oop.tl are failing. They expect an :error result, but the calls are succeeding in spite of passing too many parameters via the delegate interface. The tests/012/lambda.tl suite should catch this, but it has unfortunate weaknesses. * lib.c (funcall1, funcall2, funcall3, funcall4): When dispatching the general VM case via vm_execute_closure, check that if the closure has fewer fixed parameters than arguments we are passing, it must be variadic, or else there is an error. * tests/012/lambda.tl (call-lambda-fixed): New function. Unlike call-lambda, which uses the apply dot syntax, this switches on the argument list shape and dispatches direct calls. These compile to the CALL instruction cases with four arguments or less which will exercise funcall, funcall1, ... funcall4. Also, adding some missing test cases that probe behavior with excess arguments.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/lib.c b/lib.c
index d8293a23..11581b33 100644
--- a/lib.c
+++ b/lib.c
@@ -8525,7 +8525,9 @@ val funcall1(val fun, val arg)
case 4:
return vm_funcall4(fun, z(arg), colon_k, colon_k, colon_k);
default:
- {
+ if (!fun->f.variadic && fun->f.fixparam == 0) {
+ wrongargs(fun);
+ } else {
args_decl_constsize(args, ARGS_MIN);
args_add(args, arg);
return vm_execute_closure(fun, args);
@@ -8604,7 +8606,9 @@ val funcall2(val fun, val arg1, val arg2)
case 4:
return vm_funcall4(fun, z(arg1), z(arg2), colon_k, colon_k);
default:
- {
+ if (!fun->f.variadic && fun->f.fixparam < 2) {
+ wrongargs(fun);
+ } else {
args_decl_constsize(args, ARGS_MIN);
args_add2(args, arg1, arg2);
return vm_execute_closure(fun, args);
@@ -8685,7 +8689,9 @@ val funcall3(val fun, val arg1, val arg2, val arg3)
case 4:
return vm_funcall4(fun, z(arg1), z(arg2), z(arg3), colon_k);
default:
- {
+ if (!fun->f.variadic && fun->f.fixparam < 3) {
+ wrongargs(fun);
+ } else {
args_decl_constsize(args, ARGS_MIN);
args_add3(args, arg1, arg2, arg3);
return vm_execute_closure(fun, args);
@@ -8761,12 +8767,14 @@ val funcall4(val fun, val arg1, val arg2, val arg3, val arg4)
wrongargs(fun);
if (fun->f.functype == FVM) {
- if (fun->f.fixparam == 4)
+ if (fun->f.fixparam == 4) {
return vm_funcall4(fun, z(arg1), z(arg2), z(arg3), z(arg4));
- else {
+ } else if (fun->f.variadic || fun->f.fixparam > 4) {
args_decl(args, ARGS_MIN);
args_add4(args, arg1, arg2, arg3, arg4);
return vm_execute_closure(fun, args);
+ } else {
+ wrongargs(fun);
}
}