]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Improve handling of stack frames in filter bytecode
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 9 Mar 2022 01:32:29 +0000 (02:32 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 27 Jun 2022 19:13:32 +0000 (21:13 +0200)
When f_line is done, we have to pop the stack frame. The old code just
removed nominal number of args/vars. Change it to use stored ventry value
modified by number of returned values. This allows to allocate variables
on a stack frame during execution of f_lines instead of just at start.

But we need to know the number of returned values for a f_line. It is 1
for term, 0 for cmd. Store that to f_line during linearization.

conf/confbase.Y
filter/config.Y
filter/decl.m4
filter/f-inst.c
filter/f-inst.h
filter/f-util.c
filter/filter.c
nest/config.Y
proto/static/config.Y

index 18ca8489af5ca797ecebc47ac05f70c60da8e382..1d5738ff06d1f917cc79c93cf73cec5fe2e4c45a 100644 (file)
@@ -153,14 +153,14 @@ conf: definition ;
 definition:
    DEFINE symbol '=' term ';' {
      struct f_val *val = cfg_allocz(sizeof(struct f_val));
-     if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
+     if (f_eval(f_linearize($4, 1), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
      cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
    }
  ;
 
 expr:
    NUM
- | '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
+ | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
  | CF_SYM_KNOWN {
      if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
      $$ = SYM_VAL($1).i; }
index a3acf245289eb85e1abb6bca785636750a1e98ab..b67ca9251feaca9b935db9faeb10e889a2d3ddbb 100644 (file)
@@ -329,7 +329,7 @@ filter_def:
 
 conf: filter_eval ;
 filter_eval:
-   EVAL term { f_eval_int(f_linearize($2)); }
+   EVAL term { f_eval_int(f_linearize($2, 1)); }
  ;
 
 conf: custom_attr ;
@@ -453,7 +453,7 @@ where_filter:
 
 function_body:
    function_vars '{' cmds '}' {
-     $$ = f_linearize($3);
+     $$ = f_linearize($3, 0);
      $$->vars = $1;
    }
  ;
@@ -537,7 +537,7 @@ set_atom:
  | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
  | ENUM   { $$.type = pair_a($1); $$.val.i = pair_b($1); }
  | '(' term ')' {
-     if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
+     if (f_eval(f_linearize($2, 1), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
      if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
    }
  | CF_SYM_KNOWN {
@@ -549,13 +549,13 @@ set_atom:
 
 switch_atom:
    NUM   { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2, 1)); }
  | fipa  { $$ = $1; }
  | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
  ;
 
 cnum:
-   term { $$ = f_eval_int(f_linearize($1)); }
+   term { $$ = f_eval_int(f_linearize($1, 1)); }
 
 pair_item:
    '(' cnum ',' cnum ')'               { $$ = f_new_pair_item($2, $2, $4, $4); }
@@ -642,7 +642,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
  | switch_body switch_items ':' cmds  {
      /* Fill data fields */
      struct f_tree *t;
-     struct f_line *line = f_linearize($4);
+     struct f_line *line = f_linearize($4, 0);
      for (t = $2; t; t = t->left)
        t->data = line;
      $$ = f_merge_items($1, $2);
@@ -651,7 +651,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
      struct f_tree *t = f_new_tree();
      t->from.type = t->to.type = T_VOID;
      t->right = t;
-     t->data = f_linearize($3);
+     t->data = f_linearize($3, 0);
      $$ = f_merge_items($1, t);
  }
  ;
index 3d118e34a8197f8cc4770db5773b9847dd2054e3..4c56cd9c1d425667e5a8dd348dde924b2e8f5481 100644 (file)
@@ -216,7 +216,7 @@ whati->f$1 = f$1;
 FID_DUMP_BODY()m4_dnl
 f_dump_line(item->fl$1, indent + 1);
 FID_LINEARIZE_BODY()m4_dnl
-item->fl$1 = f_linearize(whati->f$1);
+item->fl$1 = f_linearize(whati->f$1, $2);
 FID_SAME_BODY()m4_dnl
 if (!f_same(f1->fl$1, f2->fl$1)) return 0;
 FID_ITERATE_BODY()m4_dnl
@@ -568,7 +568,7 @@ FID_WR_PUT(8)
 }
 
 struct f_line *
-f_linearize_concat(const struct f_inst * const inst[], uint count)
+f_linearize_concat(const struct f_inst * const inst[], uint count, uint results)
 {
   uint len = 0;
   for (uint i=0; i<count; i++)
@@ -580,6 +580,8 @@ f_linearize_concat(const struct f_inst * const inst[], uint count)
   for (uint i=0; i<count; i++)
     out->len = linearize(out, inst[i], out->len);
 
+    out->results = results;
+
 #ifdef LOCAL_DEBUG
   f_dump_line(out, 0);
 #endif
index e75b5e017d279a636eed5910134ad93f079a3d8e..5b8310c3c1ea31a627453540f4826cb346759f43 100644 (file)
@@ -64,7 +64,7 @@
  *     m4_dnl    ARG_ANY(num);                         argument with no type check accessible by v1, v2, v3
  *     m4_dnl    ARG_TYPE(num, type);                  just declare the type of argument
  *     m4_dnl    VARARG;                               variable-length argument list; accessible by vv(i) and whati->varcount
- *     m4_dnl    LINE(num, unused);                    this argument has to be converted to its own f_line
+ *     m4_dnl    LINE(num, out);                       this argument has to be converted to its own f_line
  *     m4_dnl    SYMBOL;                               symbol handed from config
  *     m4_dnl    STATIC_ATTR;                          static attribute definition
  *     m4_dnl    DYNAMIC_ATTR;                         dynamic attribute definition
     RESULT_TYPE(T_BOOL);
 
     if (v1.val.i)
-      LINE(2,0);
+      LINE(2,1);
     else
       RESULT_VAL(v1);
   }
     RESULT_TYPE(T_BOOL);
 
     if (!v1.val.i)
-      LINE(2,0);
+      LINE(2,1);
     else
       RESULT_VAL(v1);
   }
     if (v1.val.i)
       LINE(2,0);
     else
-      LINE(3,1);
+      LINE(3,0);
   }
 
   INST(FI_PRINT, 0, 0) {
index 58563c7906f98f99cdaf72e795515cd19ad26c81..e35f71c6f25d381d31b986f35cb50ff3465ea513 100644 (file)
@@ -46,14 +46,15 @@ struct f_line {
   uint len;                            /* Line length */
   u8 args;                             /* Function: Args required */
   u8 vars;
+  u8 results;                          /* Results left on stack: cmd -> 0, term -> 1 */
   struct f_arg *arg_list;
   struct f_line_item items[0];         /* The items themselves */
 };
 
 /* Convert the f_inst infix tree to the f_line structures */
-struct f_line *f_linearize_concat(const struct f_inst * const inst[], uint count);
-static inline struct f_line *f_linearize(const struct f_inst *root)
-{ return f_linearize_concat(&root, 1); }
+struct f_line *f_linearize_concat(const struct f_inst * const inst[], uint count, uint results);
+static inline struct f_line *f_linearize(const struct f_inst *root, uint results)
+{ return f_linearize_concat(&root, 1, results); }
 
 void f_dump_line(const struct f_line *, uint indent);
 
index 410999a640ce009895edf47e684bb9f26e9ad20d..fdb314b50bdc138e5165fa9452683eb15f5e8cb3 100644 (file)
@@ -37,7 +37,7 @@ struct filter *f_new_where(struct f_inst *where)
                                   f_new_inst(FI_DIE, F_REJECT));
 
   struct filter *f = cfg_allocz(sizeof(struct filter));
-  f->root = f_linearize(cond);
+  f->root = f_linearize(cond, 0);
   return f;
 }
 
index e505d570daf6e0898a7754ba9b8c42870d9e3dd8..20a380dc0a29f48ada71bdc8db4b989a364a43f4 100644 (file)
@@ -215,8 +215,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
     }
 
     /* End of current line. Drop local variables before exiting. */
-    fstk->vcnt -= curline.line->vars;
-    fstk->vcnt -= curline.line->args;
+    fstk->vcnt = curline.ventry + curline.line->results;
     fstk->ecnt--;
   }
 
index 179994220ef480c7c77c0cb02b661b292b3e18f1..ac599c09bc91c762a0e064a8e485be4969581b07 100644 (file)
@@ -165,7 +165,7 @@ rtrid:
 
 idval:
    NUM { $$ = $1; }
- | '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
+ | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
  | IP4 { $$ = ip4_to_u32($1); }
  | CF_SYM_KNOWN {
      if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
@@ -860,7 +860,7 @@ CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]])
 { filters_dump_all(); cli_msg(0, ""); } ;
 
 CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
-{ cmd_eval(f_linearize($2)); } ;
+{ cmd_eval(f_linearize($2, 1)); } ;
 
 CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
 CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [<buffer-size>], [[Control echoing of log messages]]) {
index 41e10dbf6ccd4d88e85193e654eb466d29961b30..9d26ee82bb8d96b22150afa3480f8e0b3cca4b1a 100644 (file)
@@ -40,7 +40,7 @@ static_route_finish(void)
   if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest)
     cf_error("Unexpected or missing nexthop/type");
 
-  this_srt->cmds = f_linearize(this_srt_cmds);
+  this_srt->cmds = f_linearize(this_srt_cmds, 0);
 }
 
 CF_DECLS