From fe4e527ce2a2fb9b6efa982b521e1397f20134af Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 5 Nov 2021 14:43:17 +0100 Subject: evaluate: clone variable expression if there is more than one reference Clone the expression that defines the variable value if there are multiple references to it in the ruleset. This saves heap memory consumption in case the variable defines a set with a huge number of elements. Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 11 ++++++++++- tests/shell/testcases/nft-f/0030variable_reuse_0 | 19 +++++++++++++++++++ .../testcases/nft-f/dumps/0030variable_reuse_0.nft | 11 +++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100755 tests/shell/testcases/nft-f/0030variable_reuse_0 create mode 100644 tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft diff --git a/src/evaluate.c b/src/evaluate.c index a268b3cb..fd7818da 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2187,7 +2187,16 @@ static int expr_evaluate_osf(struct eval_ctx *ctx, struct expr **expr) static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp) { - struct expr *new = expr_clone((*exprp)->sym->expr); + struct symbol *sym = (*exprp)->sym; + struct expr *new; + + /* If variable is reused from different locations in the ruleset, then + * clone expression. + */ + if (sym->refcnt > 2) + new = expr_clone(sym->expr); + else + new = expr_get(sym->expr); if (expr_evaluate(ctx, &new) < 0) { expr_free(new); diff --git a/tests/shell/testcases/nft-f/0030variable_reuse_0 b/tests/shell/testcases/nft-f/0030variable_reuse_0 new file mode 100755 index 00000000..8afc54aa --- /dev/null +++ b/tests/shell/testcases/nft-f/0030variable_reuse_0 @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e + +RULESET="define test = { 1.1.1.1 } + +table ip x { + set y { + type ipv4_addr + elements = { 2.2.2.2, \$test } + } + + set z { + type ipv4_addr + elements = { 3.3.3.3, \$test } + } +}" + +$NFT -f - <<< "$RULESET" diff --git a/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft new file mode 100644 index 00000000..635901f4 --- /dev/null +++ b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft @@ -0,0 +1,11 @@ +table ip x { + set y { + type ipv4_addr + elements = { 1.1.1.1, 2.2.2.2 } + } + + set z { + type ipv4_addr + elements = { 1.1.1.1, 3.3.3.3 } + } +} -- cgit v1.2.3