From 8e127e75527a02c2b3854f94b419cf8138a378cf Mon Sep 17 00:00:00 2001 From: Costa Tsaousis Date: Fri, 10 Jan 2025 16:42:37 +0000 Subject: [PATCH] disable libunwind on forked children (#19374) libunwind does not work well after fork, so we disable stack traces on forked processes --- src/libnetdata/log/nd_log-init.c | 2 ++ src/libnetdata/log/nd_log-internals.h | 2 ++ src/libnetdata/log/nd_log-libunwind.c | 30 +++++++++++++------ .../spawn_server/spawn_server_nofork.c | 2 ++ 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/libnetdata/log/nd_log-init.c b/src/libnetdata/log/nd_log-init.c index 7f846b136386a3..c3b9523e15cd90 100644 --- a/src/libnetdata/log/nd_log-init.c +++ b/src/libnetdata/log/nd_log-init.c @@ -274,6 +274,8 @@ int nd_log_systemd_journal_fd(void) { } void nd_log_reopen_log_files_for_spawn_server(const char *name) { + nd_log_forked = true; + gettid_uncached(); if(nd_log.syslog.initialized) { diff --git a/src/libnetdata/log/nd_log-internals.h b/src/libnetdata/log/nd_log-internals.h index aa27868a0fd7fe..6105f286add2e6 100644 --- a/src/libnetdata/log/nd_log-internals.h +++ b/src/libnetdata/log/nd_log-internals.h @@ -196,6 +196,8 @@ struct log_field; const char *errno_annotator(struct log_field *lf); const char *priority_annotator(struct log_field *lf); const char *timestamp_usec_annotator(struct log_field *lf); + +extern bool nd_log_forked; bool stack_trace_formatter(BUFFER *wb, void *data); #if defined(OS_WINDOWS) diff --git a/src/libnetdata/log/nd_log-libunwind.c b/src/libnetdata/log/nd_log-libunwind.c index 7ede5a5d199f53..fab1fb9c1c96d5 100644 --- a/src/libnetdata/log/nd_log-libunwind.c +++ b/src/libnetdata/log/nd_log-libunwind.c @@ -2,15 +2,25 @@ #include "nd_log-internals.h" +bool nd_log_forked = false; + #ifdef HAVE_LIBUNWIND #include bool stack_trace_formatter(BUFFER *wb, void *data __maybe_unused) { static __thread bool in_stack_trace = false; - // Prevent recursion - if(in_stack_trace) - return buffer_strcat(wb, "stack trace recursion detected"), true; + if (nd_log_forked) { + // libunwind freezes in forked children + buffer_strcat(wb, "stack trace after fork is disabled"); + return true; + } + + if (in_stack_trace) { + // Prevent recursion + buffer_strcat(wb, "stack trace recursion detected"); + return true; + } in_stack_trace = true; @@ -23,9 +33,10 @@ bool stack_trace_formatter(BUFFER *wb, void *data __maybe_unused) { unw_init_local(&cursor, &context); // Skip first 3 frames (our logging infrastructure) - unw_step(&cursor); - unw_step(&cursor); - unw_step(&cursor); + for (int i = 0; i < 3; i++) { + if (unw_step(&cursor) <= 0) + goto cleanup; // Ensure proper cleanup if unwinding fails early + } while (unw_step(&cursor) > 0) { unw_word_t offset, pc; @@ -37,17 +48,18 @@ bool stack_trace_formatter(BUFFER *wb, void *data __maybe_unused) { const char *name = sym; if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { - if(frames++) buffer_strcat(wb, "\n"); + if (frames++) buffer_strcat(wb, "\n"); buffer_sprintf(wb, "%s+0x%lx", name, (unsigned long)offset); } else { - if(frames++) + if (frames++) buffer_strcat(wb, "\n"); buffer_strcat(wb, ""); } } - in_stack_trace = false; +cleanup: + in_stack_trace = false; // Ensure the flag is reset return true; } diff --git a/src/libnetdata/spawn_server/spawn_server_nofork.c b/src/libnetdata/spawn_server/spawn_server_nofork.c index 3fd890f045f2a2..3274de3f531d16 100644 --- a/src/libnetdata/spawn_server/spawn_server_nofork.c +++ b/src/libnetdata/spawn_server/spawn_server_nofork.c @@ -1210,6 +1210,8 @@ int spawn_server_exec_kill(SPAWN_SERVER *server, SPAWN_INSTANCE *instance, int t } SPAWN_INSTANCE* spawn_server_exec(SPAWN_SERVER *server, int stderr_fd, int custom_fd, const char **argv, const void *data, size_t data_size, SPAWN_INSTANCE_TYPE type) { + if(!server) return NULL; + int pipe_stdin[2] = { -1, -1 }, pipe_stdout[2] = { -1, -1 }; SPAWN_INSTANCE *instance = callocz(1, sizeof(SPAWN_INSTANCE));