When vars_check_arg() allocates memory for variable names using
my_strndup(), it stores the pointer in desc.name but fails to set the
VDF_NAME_ALLOCATED flag. This flag is essential for proper cleanup
since release_sample_arg() uses it to determine whether to free the
allocated memory.

Additionally, release_sample_arg() was missing handling for ARGT_VAR
type arguments, causing the allocated variable names to never be freed
when sample expressions are released.

The memory leak was detected by AddressSanitizer during regression
tests with the following stack trace:

  Direct leak of 12 byte(s) in 2 object(s) allocated from:
      #0 __interceptor_malloc
      #1 my_strndup src/tools.c:3033
      #2 vars_check_arg src/vars.c:840
      #3 sample_parse_expr src/sample.c:1290
      ...
      #9 httpclient_resolve_init src/http_client.c:1076

This patch fixes the issue by:
  1. Setting VDF_NAME_ALLOCATED flag in vars_check_arg() after
     allocating the variable name
  2. Adding ARGT_VAR handling in release_sample_arg() to free the
     allocated name when the flag is set

The fix follows the same pattern already used in parse_store() and
release_store_rule() for handling allocated variable names.

Tested with:
  - ASAN-enabled build on Linux (TARGET=linux-glibc USE_OPENSSL=1
    ARCH_FLAGS="-g -fsanitize=address")
  - Regression tests: reg-tests/sample_fetches/vars.vtc
  - Regression tests: reg-tests/startup/default_rules.vtc
---
 src/sample.c | 4 ++++
 src/vars.c   | 1 +
 2 files changed, 5 insertions(+)

diff --git a/src/sample.c b/src/sample.c
index 31fe56fd8..a35d997f7 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -1741,6 +1741,10 @@ static void release_sample_arg(struct arg *p)
                        regex_free(p->data.reg);
                        p->data.reg = NULL;
                }
+               else if (p->type == ARGT_VAR) {
+                       if (p->data.var.flags & VDF_NAME_ALLOCATED)
+                               ha_free((char **)&p->data.var.name);
+               }
                p++;
        }
 
diff --git a/src/vars.c b/src/vars.c
index 8cd0819ad..1b72ebb2e 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -844,6 +844,7 @@ int vars_check_arg(struct arg *arg, char **err)
                }
 
                desc.name = saved_name;
+               desc.flags |= VDF_NAME_ALLOCATED;
        }
 
        if (desc.scope == SCOPE_PROC && !var_set(&desc, &empty_smp, 
VF_CREATEONLY|VF_PERMANENT)) {
-- 
2.48.1



Reply via email to