BUG/MINOR: log: properly free memory on logformat parse error and deinit()

This patch may be backported to all supported versions.
diff --git a/src/haproxy.c b/src/haproxy.c
index ec66103..93ce987 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -2249,11 +2249,15 @@
 
 		list_for_each_entry_safe(lf, lfb, &p->logformat, list) {
 			LIST_DEL(&lf->list);
+			release_sample_expr(lf->expr);
+			free(lf->arg);
 			free(lf);
 		}
 
 		list_for_each_entry_safe(lf, lfb, &p->logformat_sd, list) {
 			LIST_DEL(&lf->list);
+			release_sample_expr(lf->expr);
+			free(lf->arg);
 			free(lf);
 		}
 
diff --git a/src/log.c b/src/log.c
index 49de570..866ff23 100644
--- a/src/log.c
+++ b/src/log.c
@@ -377,7 +377,7 @@
 int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
 {
 	int j;
-	struct logformat_node *node;
+	struct logformat_node *node = NULL;
 
 	for (j = 0; logformat_keywords[j].name; j++) { // search a log type
 		if (strlen(logformat_keywords[j].name) == var_len &&
@@ -386,14 +386,14 @@
 				node = calloc(1, sizeof(*node));
 				if (!node) {
 					memprintf(err, "out of memory error");
-					return 0;
+					goto error_free;
 				}
 				node->type = logformat_keywords[j].type;
 				node->options = *defoptions;
 				if (arg_len) {
 					node->arg = my_strndup(arg, arg_len);
 					if (!parse_logformat_var_args(node->arg, node, err))
-						return 0;
+						goto error_free;
 				}
 				if (node->type == LOG_FMT_GLOBAL) {
 					*defoptions = node->options;
@@ -402,7 +402,7 @@
 				} else {
 					if (logformat_keywords[j].config_callback &&
 					    logformat_keywords[j].config_callback(node, curproxy) != 0) {
-						return 0;
+						goto error_free;
 					}
 					curproxy->to_log |= logformat_keywords[j].lw;
 					LIST_ADDQ(list_format, &node->list);
@@ -415,7 +415,7 @@
 			} else {
 				memprintf(err, "format variable '%s' is reserved for HTTP mode",
 				          logformat_keywords[j].name);
-				return 0;
+				goto error_free;
 			}
 		}
 	}
@@ -424,6 +424,12 @@
 	var[var_len] = 0;
 	memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
 	var[var_len] = j;
+
+  error_free:
+	if (node) {
+		free(node->arg);
+		free(node);
+	}
 	return 0;
 }
 
@@ -476,8 +482,8 @@
 int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err)
 {
 	char *cmd[2];
-	struct sample_expr *expr;
-	struct logformat_node *node;
+	struct sample_expr *expr = NULL;
+	struct logformat_node *node = NULL;
 	int cmd_arg;
 
 	cmd[0] = text;
@@ -487,13 +493,13 @@
 	expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args);
 	if (!expr) {
 		memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
-		return 0;
+		goto error_free;
 	}
 
 	node = calloc(1, sizeof(*node));
 	if (!node) {
 		memprintf(err, "out of memory error");
-		return 0;
+		goto error_free;
 	}
 	node->type = LOG_FMT_EXPR;
 	node->expr = expr;
@@ -502,7 +508,7 @@
 	if (arg_len) {
 		node->arg = my_strndup(arg, arg_len);
 		if (!parse_logformat_var_args(node->arg, node, err))
-			return 0;
+			goto error_free;
 	}
 	if (expr->fetch->val & cap & SMP_VAL_REQUEST)
 		node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
@@ -511,11 +517,9 @@
 		node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
 
 	if (!(expr->fetch->val & cap)) {
-		free(node);
-		node = NULL;
 		memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
 		          text, sample_src_names(expr->fetch->use));
-		return 0;
+		goto error_free;
 	}
 
 	/* check if we need to allocate an hdr_idx struct for HTTP parsing */
@@ -530,6 +534,14 @@
 	curpx->to_log |= LW_REQ;
 	LIST_ADDQ(list_format, &node->list);
 	return 1;
+
+  error_free:
+	release_sample_expr(expr);
+	if (node) {
+		free(node->arg);
+		free(node);
+	}
+	return 0;
 }
 
 /*
@@ -567,6 +579,8 @@
 	/* flush the list first. */
 	list_for_each_entry_safe(tmplf, back, list_format, list) {
 		LIST_DEL(&tmplf->list);
+		release_sample_expr(tmplf->expr);
+		free(tmplf->arg);
 		free(tmplf);
 	}