Log servers are a real mess because:
- entries are duplicated using memcpy() without their strings being
reallocated, which results in these ones not being freeable every
time.
- a new field, ring_name, was added in 2.2 by commit
99c453df9
("MEDIUM: ring: new section ring to declare custom ring buffers.")
but it's never initialized during copies, causing the same issue
- no attempt is made at freeing all that.
Of course, running "haproxy -c" under ASAN quickly notices that and
dumps a core.
This patch adds the missing strdup() and initialization where required,
adds a new free_logsrv() function to cleanly free() such a structure,
calls it from the proxy when iterating over logsrvs instead of silently
leaking their file names and ring names, and adds the same logsrv loop
to the proxy_free_defaults() function so that we don't leak defaults
sections on exit.
It looks a bit entangled, but it comes as a whole because all this stuff
is inter-dependent and was missing.
It's probably preferable not to backport this in the foreseable future
as it may reveal other jokes if some obscure parts continue to memcpy()
the logsrv struct.
*/
int parse_logformat_string(const char *str, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err);
+void free_logsrv(struct logsrv *logsrv);
+
/* Parse "log" keyword and update the linked list. */
int parse_logsrv(char **args, struct list *logsrvs, int do_del, const char *file, int linenum, char **err);
memcpy(node, logsrv, sizeof(*node));
LIST_INIT(&node->list);
LIST_APPEND(&curproxy->logsrvs, &node->list);
+ node->ring_name = NULL;
+ node->conf.file = NULL;
+ node->conf.line = 0;
}
if (curproxy->conf.logformat_string) {
curproxy->conf.args.ctx = ARGC_LOG;
return 0;
}
+/* frees log server <logsrv> after freeing all of its allocated fields. The
+ * server must not belong to a list anymore. Logsrv may be NULL, which is
+ * silently ignored.
+ */
+void free_logsrv(struct logsrv *logsrv)
+{
+ if (!logsrv)
+ return;
+
+ BUG_ON(LIST_INLIST(&logsrv->list));
+ ha_free(&logsrv->conf.file);
+ ha_free(&logsrv->ring_name);
+ free(logsrv);
+}
+
/*
* Parse "log" keyword and update <logsrvs> list accordingly.
*
}
list_for_each_entry_safe(logsrv, back, logsrvs, list) {
- LIST_DELETE(&logsrv->list);
- free(logsrv);
+ LIST_DEL_INIT(&logsrv->list);
+ free_logsrv(logsrv);
}
return 1;
}
node->ref = logsrv;
LIST_INIT(&node->list);
LIST_APPEND(logsrvs, &node->list);
+ node->ring_name = logsrv->ring_name ? strdup(logsrv->ring_name) : NULL;
node->conf.file = strdup(file);
node->conf.line = linenum;
error:
free(smp_rgs);
- if (logsrv) {
- free(logsrv->conf.file);
- free(logsrv->ring_name);
- }
- free(logsrv);
+ free_logsrv(logsrv);
return 0;
}
}
list_for_each_entry_safe(log, logb, &p->logsrvs, list) {
- LIST_DELETE(&log->list);
- free(log);
+ LIST_DEL_INIT(&log->list);
+ free_logsrv(log);
}
list_for_each_entry_safe(lf, lfb, &p->logformat, list) {
void proxy_free_defaults(struct proxy *defproxy)
{
struct acl *acl, *aclb;
+ struct logsrv *log, *logb;
ha_free(&defproxy->id);
ha_free(&defproxy->conf.file);
if (defproxy->conf.logformat_sd_string != default_rfc5424_sd_log_format)
ha_free(&defproxy->conf.logformat_sd_string);
+ list_for_each_entry_safe(log, logb, &defproxy->logsrvs, list) {
+ LIST_DEL_INIT(&log->list);
+ free_logsrv(log);
+ }
+
ha_free(&defproxy->conf.uniqueid_format_string);
ha_free(&defproxy->conf.error_logformat_string);
ha_free(&defproxy->conf.lfs_file);
node->ref = tmplogsrv->ref;
LIST_INIT(&node->list);
LIST_APPEND(&curproxy->logsrvs, &node->list);
+ node->ring_name = tmplogsrv->ring_name ? strdup(tmplogsrv->ring_name) : NULL;
+ node->conf.file = strdup(tmplogsrv->conf.file);
+ node->conf.line = tmplogsrv->conf.line;
}
curproxy->conf.uniqueid_format_string = defproxy->conf.uniqueid_format_string;