]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Reintroduce checking of function argument types oz-improve-functions
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Mon, 21 Oct 2019 19:55:57 +0000 (21:55 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Mon, 21 Oct 2019 20:00:46 +0000 (22:00 +0200)
Seems like during filter rewrite we lost type validation for function
arguments.

filter/config.Y
filter/data.h
filter/f-inst.c
filter/filter.h

index 08c861ce885ddbadad05bc5d49d05440bab2c9d7..d89c9884797c2d6a3e2b1f785200d9bbccae951c 100644 (file)
@@ -10,6 +10,7 @@
 
 CF_HDR
 
+#include "lib/buffer.h"
 #include "filter/f-inst.h"
 #include "filter/data.h"
 
@@ -22,6 +23,8 @@ static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
 #define f_generate_complex(fi_code, da, arg) \
   f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
 
+BUFFER_(struct f_arg) this_args;
+
 /*
  * Sets and their items are during parsing handled as lists, linked
  * through left ptr. The first item in a list also contains a pointer
@@ -455,7 +458,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 %type <flv> lvalue
 %type <i> type function_args function_vars
 %type <ecs> ec_kind
-%type <fret> break_command 
+%type <fret> break_command
 %type <i32> cnum
 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
 %type <trie> fprefix_set
@@ -553,20 +556,27 @@ type:
    }
  ;
 
+function_arg:
+   type symbol {
+     cf_define_symbol($2, SYM_VARIABLE | $1, offset, $2->scope->slots++);
+     BUFFER_PUSH(this_args) = (struct f_arg){ .type = $1 };
+   }
+ ;
+
 function_argsn:
-   /* EMPTY */
- | function_argsn type symbol ';' {
-     if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
-     cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
+   /* EMPTY */ {
+     /* Initialize the buffer */
+     if (!this_args.data)
+       BUFFER_INIT(this_args, &root_pool, 4);
+     else
+       BUFFER_FLUSH(this_args);
    }
+ | function_argsn function_arg ';'
  ;
 
 function_args:
    '(' ')' { $$ = 0; }
- | '(' function_argsn type symbol ')' {
-     cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
-     $$ = $4->scope->slots;
-   }
+ | '(' function_argsn function_arg ')' { $$ = this_args.used; }
  ;
 
 function_vars:
@@ -615,7 +625,13 @@ function_def:
      struct function *fn = cfg_alloc(sizeof(struct function));
      *fn = (struct function) { .sym = $2, .body = $5 };
      $2->function = fn;
-     $5->args = $4;
+     if ($4) {
+       struct f_arg *args = cfg_alloc(BUFFER_SIZE(this_args));
+       memcpy(args, this_args.data, BUFFER_SIZE(this_args));
+       fn->args = args;
+       fn->arg_count = this_args.used;
+     }
+     $5->args = fn->arg_count;
      cf_pop_scope();
    }
  ;
index 083595f4c2937da059e902adcb096b8320a8546c..b0db4f11481054c45e93cf665311d1b045ec3e71 100644 (file)
@@ -80,6 +80,10 @@ struct f_val {
   } val;
 };
 
+struct f_arg {
+  enum f_type type;
+};
+
 /* Dynamic attribute definition (eattrs) */
 struct f_dynamic_attr {
   u8 type;             /* EA type (EAF_*) */
index c21d48df64b42d735d08c828e23c5293f202b915..4fec9fc36c478dfba051092bcc31f990428f02c1 100644 (file)
     SYMBOL;
 
     FID_NEW_BODY()
-      if (whati->varcount != sym->function->body->args)
+      const struct function *fn = sym->function;
+
+      if (whati->varcount != fn->arg_count)
        cf_error("Function call '%s' got %u arguments, needs %u arguments",
-                sym->name, whati->varcount, sym->function->body->args);
+                sym->name, whati->varcount, fn->arg_count);
 
       /* Add void slot for return value (requires [[NEVER_CONSTANT]]) */
       struct f_inst *rv = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
        return 0;
 
     FID_INTERPRET_BODY()
+    const struct function *fn = sym->function;
+
+    /* Check types of arguments */
+    for (uint i = 0; i < fn->arg_count; i++)
+      if ((vv(i).type != fn->args[i].type) && (vv(i).type != T_VOID))
+      {
+       /* IP->Quad implicit conversion */
+       if ((fn->args[i].type == T_QUAD) && val_is_ip4(&vv(i)))
+         vv(i) = (struct f_val) {
+           .type = T_QUAD,
+           .val.i = ipa_to_u32(vv(i).val.ip),
+         };
+       else
+         runtime("Function call '%s' argument %u must be of type 0x%02x, got 0x%02x",
+                 sym->name, i, fn->args[i].type, vv(i).type);
+      }
 
     /* Push the body on stack */
     LINEX(sym->function->body);
index 8b790e370faed04d02fd2728dcc2af98684b3d99..5f82de560364a01cba174a01aef8596cc008645c 100644 (file)
@@ -53,7 +53,9 @@ struct filter {
 
 struct function {
   struct symbol *sym;
+  const struct f_arg *args;
   const struct f_line *body;
+  uint arg_count;
 };
 
 struct rte;