From c1c88f4809092bbf9ba1d6f56cbc46f0e3fee146 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 8 Sep 2021 15:03:58 +0200 Subject: [PATCH] MEDIUM: vars: make var_clear() only reset VF_PERMANENT variables We certainly do not want that a permanent variable (one that is listed in the configuration) be erased by accident by an "unset-var" action. Let's make sure these ones are only reset to an empty sample, like at the moment of their initial registration. One trick is that the same function is used to purge the memory at the end and to delete, so we need to add an extra "force" argument to make the choice. --- include/haproxy/vars.h | 2 +- src/vars.c | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/haproxy/vars.h b/include/haproxy/vars.h index a40dce028..bc27e3798 100644 --- a/include/haproxy/vars.h +++ b/include/haproxy/vars.h @@ -31,7 +31,7 @@ extern struct vars proc_vars; void vars_init_head(struct vars *vars, enum vars_scope scope); void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size); -unsigned int var_clear(struct var *var); +unsigned int var_clear(struct var *var, int force); void vars_prune(struct vars *vars, struct session *sess, struct stream *strm); void vars_prune_per_sess(struct vars *vars); int vars_get_by_name(const char *name, size_t len, struct sample *smp, const struct buffer *def); diff --git a/src/vars.c b/src/vars.c index 30aff97e8..6fc58dd33 100644 --- a/src/vars.c +++ b/src/vars.c @@ -142,8 +142,11 @@ scope_sess: return 1; } -/* This fnuction remove a variable from the list and free memory it used */ -unsigned int var_clear(struct var *var) +/* This function removes a variable from the list and frees the memory it was + * using. If the variable is marked "VF_PERMANENT", the sample_data is only + * reset to SMP_T_ANY unless is non nul. Returns the freed size. + */ +unsigned int var_clear(struct var *var, int force) { unsigned int size = 0; @@ -155,9 +158,14 @@ unsigned int var_clear(struct var *var) ha_free(&var->data.u.meth.str.area); size += var->data.u.meth.str.data; } - LIST_DELETE(&var->l); - pool_free(var_pool, var); - size += sizeof(struct var); + /* wipe the sample */ + var->data.type = SMP_T_ANY; + + if (!(var->flags & VF_PERMANENT) || force) { + LIST_DELETE(&var->l); + pool_free(var_pool, var); + size += sizeof(struct var); + } return size; } @@ -171,7 +179,7 @@ void vars_prune(struct vars *vars, struct session *sess, struct stream *strm) HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock); list_for_each_entry_safe(var, tmp, &vars->head, l) { - size += var_clear(var); + size += var_clear(var, 1); } HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock); var_accounting_diff(vars, sess, strm, -size); @@ -187,7 +195,7 @@ void vars_prune_per_sess(struct vars *vars) HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock); list_for_each_entry_safe(var, tmp, &vars->head, l) { - size += var_clear(var); + size += var_clear(var, 1); } HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock); @@ -494,7 +502,7 @@ static int var_unset(const char *name, enum vars_scope scope, struct sample *smp HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock); var = var_get(vars, name); if (var) { - size = var_clear(var); + size = var_clear(var, 0); var_accounting_diff(vars, smp->sess, smp->strm, -size); } HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);