From b3fdba0bf8ffe9d116adcb77b8e90fe753b8d9bb Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 20 Oct 2019 20:27:06 +0200 Subject: [PATCH] Filter: Update filter functions to use VARARG Make function call one instruction with variable arguments, instead of independently setting up arguments and then calling the function. This fixes code that assumes every term to be one instruction (plus recursive arguments). --- filter/config.Y | 28 ++++++---------------------- filter/decl.m4 | 3 ++- filter/f-inst.c | 23 +++++++++++++++++------ 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 340053ba..ff1d3cb3 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -447,7 +447,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc ELSE %type cmds_int cmd_prep -%type term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail +%type term block cmd cmds constant constructor print_list args function_call symbol_value bgp_path_expr bgp_path bgp_path_tail %type dynamic_attr %type static_attr %type filter where_filter @@ -844,33 +844,17 @@ constructor: ; -/* This generates the function_call variable list backwards. */ -var_list: /* EMPTY */ { $$ = NULL; } +args: + /* EMPTY */ { $$ = NULL; } | term { $$ = $1; } - | var_list ',' term { $$ = $3; $$->next = $1; } + | term ',' args { $$ = $1; $$->next = $3; } function_call: - CF_SYM_KNOWN '(' var_list ')' { + CF_SYM_KNOWN '(' args ')' { if ($1->class != SYM_FUNCTION) cf_error("You can't call something which is not a function. Really."); - struct f_inst *fc = f_new_inst(FI_CALL, $1); - uint args = 0; - while ($3) { - args++; - struct f_inst *tmp = $3->next; - $3->next = fc; - - fc = $3; - $3 = tmp; - } - - if (args != $1->function->args) - cf_error("Function call '%s' got %u arguments, need %u arguments.", - $1->name, args, $1->function->args); - - $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); - $$->next = fc; + $$ = f_new_inst(FI_CALL, $3, $1); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index 4d5b70dc..a2ddcf3d 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -274,7 +274,8 @@ m4_undivert(102)m4_dnl [[m4_dnl The one case in The Big Switch inside interpreter case INST_NAME(): #define whati (&(what->i_]]INST_NAME()[[)) - m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) + m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[ if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); + fstk->vcnt -= INST_INVAL(); ]]) m4_undivert(108)m4_dnl #undef whati break; diff --git a/filter/f-inst.c b/filter/f-inst.c index 385d18d0..ad3ef3f6 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -895,25 +895,36 @@ INST(FI_CALL, 0, 1) { NEVER_CONSTANT; + VARARG; SYMBOL; + FID_NEW_BODY() + if (whati->varcount != sym->function->args) + cf_error("Function call '%s' got %u arguments, needs %u arguments", + sym->name, whati->varcount, sym->function->args); + + /* Add void slot for return value (requires [[NEVER_CONSTANT]]) */ + struct f_inst *rv = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); + rv->next = whati->fvar; + whati->fvar = rv; + what->size += rv->size; + FID_SAME_BODY() if (!(f2->sym->flags & SYM_FLAG_SAME)) return 0; + FID_INTERPRET_BODY() /* Push the body on stack */ LINEX(sym->function); curline.emask |= FE_RETURN; - /* Before this instruction was called, there was the T_VOID - * automatic return value pushed on value stack and also - * sym->function->args function arguments. Setting the - * vbase to point to first argument. */ - ASSERT(curline.ventry >= sym->function->args); - curline.ventry -= sym->function->args; + /* Set new base for local variables */ curline.vbase = curline.ventry; + /* Arguments were substracted by [[VARARG]], now add them back */ + fstk->vcnt += whati->varcount; + /* Storage for local variables */ memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars); fstk->vcnt += sym->function->vars;