]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Reducing filter stack size to allow for lesser thread stack size
authorMaria Matejka <mq@ucw.cz>
Wed, 25 Aug 2021 20:20:48 +0000 (22:20 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 10 Sep 2021 16:11:28 +0000 (18:11 +0200)
conf/conf.h
filter/config.Y
filter/decl.m4
filter/f-inst.c
filter/filter.c
test/birdtest.c

index 3bc37959ff54c5f52d4de6599afc0ac5cc7f95de..55cb9c58780617007bdcb8b1bbe37cfbe39e7928 100644 (file)
@@ -35,6 +35,7 @@ struct config {
   u32 proto_default_debug;             /* Default protocol debug mask */
   u32 proto_default_mrtdump;           /* Default protocol mrtdump mask */
   u32 channel_default_debug;           /* Default channel debug mask */
+  u16 filter_vstk, filter_estk;                /* Filter stack depth */
   struct timeformat tf_route;          /* Time format for 'show route' */
   struct timeformat tf_proto;          /* Time format for 'show protocol' */
   struct timeformat tf_log;            /* Time format for the logfile */
index 7820e719d65298e2a16c07203a8e706ff9c50794..e6b59cbe99169f54f03a0a4f8446027ad9d00687 100644 (file)
@@ -288,7 +288,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
        EMPTY,
        FILTER, WHERE, EVAL, ATTRIBUTE,
-       BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
+       BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
 
 %nonassoc THEN
 %nonassoc ELSE
@@ -312,6 +312,12 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 
 CF_GRAMMAR
 
+conf: FILTER STACKS expr expr ';' {
+  new_config->filter_vstk = $3;
+  new_config->filter_estk = $4;
+ }
+ ;
+
 conf: filter_def ;
 filter_def:
    FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
index 6e135bbc01c8ebb15d75a9f8057934d28ce9aa0f..44537aaa5a02b579200b9549cda038276b2d709c 100644 (file)
@@ -195,6 +195,7 @@ FID_INTERPRET_BODY()')
 #      that was needed in the former implementation.
 m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()')
 m4_define(LINEX_, `do {
+  if (fstk->ecnt + 1 >= fstk->elen) runtime("Filter execution stack overflow");
   fstk->estk[fstk->ecnt].pos = 0;
   fstk->estk[fstk->ecnt].line = $1;
   fstk->estk[fstk->ecnt].ventry = fstk->vcnt;
@@ -232,7 +233,7 @@ FID_INTERPRET_BODY()')
 #      state the result and put it to the right place.
 m4_define(RESULT, `RESULT_TYPE([[$1]]) RESULT_([[$1]],[[$2]],[[$3]])')
 m4_define(RESULT_, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
-m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]],
+m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; f_vcnt_check_overflow(1); fstk->vcnt++; } while (0)]],
 [[return fi_constant(what, $1)]])')
 m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])')
 
index b876a937226583aa6ce58b436489399c3026c5c7..7c757e741d795f04549f5ce25a8e0258ff659616 100644 (file)
     curline.vbase = curline.ventry;
 
     /* Storage for local variables */
+    f_vcnt_check_overflow(sym->function->vars);
     memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
     fstk->vcnt += sym->function->vars;
   }
index e505d570daf6e0898a7754ba9b8c42870d9e3dd8..7004b96d63beb9f24307db2c364be9de144f7429 100644 (file)
@@ -50,30 +50,28 @@ enum f_exception {
   FE_RETURN = 0x1,
 };
 
-
-struct filter_stack {
-  /* Value stack for execution */
-#define F_VAL_STACK_MAX        4096
-  uint vcnt;                           /* Current value stack size; 0 for empty */
-  uint ecnt;                           /* Current execute stack size; 0 for empty */
-
-  struct f_val vstk[F_VAL_STACK_MAX];  /* The stack itself */
-
-  /* Instruction stack for execution */
-#define F_EXEC_STACK_MAX 4096
-  struct {
-    const struct f_line *line;         /* The line that is being executed */
-    uint pos;                          /* Instruction index in the line */
-    uint ventry;                       /* Value stack depth on entry */
-    uint vbase;                                /* Where to index variable positions from */
-    enum f_exception emask;            /* Exception mask */
-  } estk[F_EXEC_STACK_MAX];
+struct filter_exec_stack {
+  const struct f_line *line;           /* The line that is being executed */
+  uint pos;                            /* Instruction index in the line */
+  uint ventry;                         /* Value stack depth on entry */
+  uint vbase;                          /* Where to index variable positions from */
+  enum f_exception emask;              /* Exception mask */
 };
 
 /* Internal filter state, to be allocated on stack when executing filters */
 struct filter_state {
   /* Stacks needed for execution */
-  struct filter_stack *stack;
+  struct filter_stack {
+    /* Current filter stack depth */
+
+    /* Value stack */
+    uint vcnt, vlen;
+    struct f_val *vstk;
+
+    /* Instruction stack for execution */
+    uint ecnt, elen;
+    struct filter_exec_stack *estk;
+  } stack;
 
   /* The route we are processing. This may be NULL to indicate no route available. */
   struct rte **rte;
@@ -95,10 +93,13 @@ struct filter_state {
 };
 
 _Thread_local static struct filter_state filter_state;
-_Thread_local static struct filter_stack filter_stack;
 
 void (*bt_assert_hook)(int result, const struct f_line_item *assert);
 
+#define _f_stack_init(fs, px, def) ((fs).stack.px##stk = alloca(sizeof(*(fs).stack.px##stk) * ((fs).stack.px##len = (config && config->filter_##px##stk) ? config->filter_##px##stk : (def))))
+
+#define f_stack_init(fs) ( _f_stack_init(fs, v, 128), _f_stack_init(fs, e, 128) )
+
 static inline void f_cache_eattrs(struct filter_state *fs)
 {
   fs->eattrs = &((*fs->rte)->attrs->eattrs);
@@ -163,15 +164,17 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
   ASSERT(line->args == 0);
 
   /* Initialize the filter stack */
-  struct filter_stack *fstk = fs->stack;
+  struct filter_stack *fstk = &fs->stack;
 
   fstk->vcnt = line->vars;
   memset(fstk->vstk, 0, sizeof(struct f_val) * line->vars);
 
   /* The same as with the value stack. Not resetting the stack for performance reasons. */
   fstk->ecnt = 1;
-  fstk->estk[0].line = line;
-  fstk->estk[0].pos = 0;
+  fstk->estk[0] = (struct filter_exec_stack) {
+    .line = line,
+    .pos = 0,
+  };
 
 #define curline fstk->estk[fstk->ecnt-1]
 
@@ -191,6 +194,8 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
 #define v2 vv(1)
 #define v3 vv(2)
 
+#define f_vcnt_check_overflow(n) do { if (fstk->vcnt + n >= fstk->vlen) runtime("Filter execution stack overflow"); } while (0)
+
 #define runtime(fmt, ...) do { \
   if (!(fs->flags & FF_SILENT)) \
     log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
@@ -276,12 +281,13 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
 
   /* Initialize the filter state */
   filter_state = (struct filter_state) {
-    .stack = &filter_stack,
     .rte = rte,
     .pool = tmp_pool,
     .flags = flags,
   };
 
+  f_stack_init(filter_state);
+
   LOG_BUFFER_INIT(filter_state.buf);
 
   /* Run the interpreter itself */
@@ -340,11 +346,12 @@ enum filter_return
 f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
 {
   filter_state = (struct filter_state) {
-    .stack = &filter_stack,
     .rte = rte,
     .pool = tmp_pool,
   };
 
+  f_stack_init(filter_state);
+
   LOG_BUFFER_INIT(filter_state.buf);
 
   ASSERT(!((*rte)->flags & REF_COW));
@@ -363,10 +370,11 @@ enum filter_return
 f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
 {
   filter_state = (struct filter_state) {
-    .stack = &filter_stack,
     .pool = tmp_pool,
   };
 
+  f_stack_init(filter_state);
+
   LOG_BUFFER_INIT(filter_state.buf);
 
   enum filter_return fret = interpret(&filter_state, expr, pres);
@@ -383,10 +391,11 @@ f_eval_int(const struct f_line *expr)
 {
   /* Called independently in parse-time to eval expressions */
   filter_state = (struct filter_state) {
-    .stack = &filter_stack,
     .pool = cfg_mem,
   };
 
+  f_stack_init(filter_state);
+
   struct f_val val;
 
   LOG_BUFFER_INIT(filter_state.buf);
index a1da078fcf2fb7aa30ad18f824b5479ef8c6b464..745118d0f848bb227fa4db408b007b9d5f296834 100644 (file)
@@ -240,7 +240,7 @@ bt_log_result(int result, u64 time, const char *fmt, va_list argptr)
   printf("%s\n", result_str);
 
   if (do_die && !result)
-    abort();
+    exit(1);
 }
 
 static u64