From 935278dff3c97083e33ce46a71857abb57c89ef3 Mon Sep 17 00:00:00 2001 From: Pablo Garcia Caceres Date: Tue, 18 Aug 2026 16:15:08 +0200 Subject: [PATCH 1/2] log: release resources when flb_log_create fails flb_log_create() did not return after flb_worker_context_create() failed, so execution fell through to flb_log_worker_init() with a freed log and a NULL worker. Return NULL there, and release what has actually been set up: the failure paths that run after the channel manager pipe exists were freeing only the event loop and the context, leaking the pipe descriptors, the cmetrics state and, when FLB_LOG_FILE was selected, an open log file. Because config->log is cleared on those paths, flb_config_exit() cannot reach flb_log_destroy() to clean up later, so a caller that retries after a transient allocation failure leaks on every attempt. flb_log_destroy() cannot be reused for this: it joins log->tid and dereferences log->worker, neither of which exists before the collector thread starts. log_create_cleanup() covers the pre-thread subset. Signed-off-by: Pablo Garcia Caceres --- src/flb_log.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/flb_log.c b/src/flb_log.c index 8fb090737c9..03549c78154 100644 --- a/src/flb_log.c +++ b/src/flb_log.c @@ -1001,6 +1001,25 @@ struct flb_log_metrics *flb_log_metrics_create() return metrics; } +/* + * Release everything flb_log_create() has set up so far, for the failure + * paths that run after the channel manager pipe exists but before the + * collector thread is started. flb_log_destroy() cannot be used there: it + * joins log->tid and dereferences log->worker, neither of which is valid + * yet. + */ +static void log_create_cleanup(struct flb_log *log, struct flb_config *config) +{ + flb_log_metrics_destroy(log->metrics); + flb_pipe_destroy(log->ch_mng); + log_close_sink(log); + pthread_mutex_destroy(&log->queue_mutex); + pthread_mutex_destroy(&log->pipeline_queue.mutex); + mk_event_loop_destroy(log->evl); + flb_free(log); + config->log = NULL; +} + struct flb_log *flb_log_create(struct flb_config *config, int type, int level, char *out) { @@ -1063,9 +1082,7 @@ struct flb_log *flb_log_create(struct flb_config *config, int type, if (ret == -1) { fprintf(stderr, "[log] could not register event\n"); - mk_event_loop_destroy(log->evl); - flb_free(log); - config->log = NULL; + log_create_cleanup(log, config); return NULL; } @@ -1073,9 +1090,7 @@ struct flb_log *flb_log_create(struct flb_config *config, int type, log->metrics = flb_log_metrics_create(); if (log->metrics == NULL) { fprintf(stderr, "[log] could not create log metrics\n"); - mk_event_loop_destroy(log->evl); - flb_free(log); - config->log = NULL; + log_create_cleanup(log, config); return NULL; } @@ -1087,9 +1102,8 @@ struct flb_log *flb_log_create(struct flb_config *config, int type, worker = flb_worker_context_create(NULL, NULL, config); if (!worker) { flb_errno(); - mk_event_loop_destroy(log->evl); - flb_free(log); - config->log = NULL; + log_create_cleanup(log, config); + return NULL; } /* Set the worker context global */ @@ -1099,9 +1113,7 @@ struct flb_log *flb_log_create(struct flb_config *config, int type, ret = flb_log_worker_init(worker); if (ret == -1) { flb_errno(); - mk_event_loop_destroy(log->evl); - flb_free(log); - config->log = NULL; + log_create_cleanup(log, config); flb_free(worker); return NULL; } From b2124897d045bdc5ebd32e4f71fea327c0f4a0e9 Mon Sep 17 00:00:00 2001 From: MsfPablo Date: Sat, 22 Aug 2026 18:26:27 +0200 Subject: [PATCH 2/2] log: release worker context and log resources on flb_worker_create failure --- src/flb_log.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/flb_log.c b/src/flb_log.c index 03549c78154..cda79bdbc27 100644 --- a/src/flb_log.c +++ b/src/flb_log.c @@ -1020,6 +1020,22 @@ static void log_create_cleanup(struct flb_log *log, struct flb_config *config) config->log = NULL; } +/* + * Release the fake worker context flb_log_create() builds for the main + * thread. The thread-local pointer is cleared too, otherwise it would be + * left dangling for any later flb_log_create() attempt. + */ +static void log_create_worker_cleanup(struct flb_worker *worker) +{ + if (worker->log_cache) { + flb_log_cache_destroy(worker->log_cache); + worker->log_cache = NULL; + } + flb_log_worker_destroy(worker); + flb_free(worker); + FLB_TLS_SET(flb_worker_ctx, NULL); +} + struct flb_log *flb_log_create(struct flb_config *config, int type, int level, char *out) { @@ -1114,7 +1130,7 @@ struct flb_log *flb_log_create(struct flb_config *config, int type, if (ret == -1) { flb_errno(); log_create_cleanup(log, config); - flb_free(worker); + log_create_worker_cleanup(worker); return NULL; } log->worker = worker; @@ -1132,10 +1148,10 @@ struct flb_log *flb_log_create(struct flb_config *config, int type, ret = flb_worker_create(log_worker_collector, log, &log->tid, config); if (ret == -1) { pthread_mutex_unlock(&log->pth_mutex); - mk_event_loop_destroy(log->evl); - flb_free(log->worker); - flb_free(log); - config->log = NULL; + pthread_mutex_destroy(&log->pth_mutex); + pthread_cond_destroy(&log->pth_cond); + log_create_worker_cleanup(log->worker); + log_create_cleanup(log, config); return NULL; }