Skip to content

Commit

Permalink
disable libunwind on forked children (netdata#19374)
Browse files Browse the repository at this point in the history
libunwind does not work well after fork, so we disable stack traces on forked processes
  • Loading branch information
ktsaou authored Jan 10, 2025
1 parent 09f043b commit 8e127e7
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/libnetdata/log/nd_log-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/libnetdata/log/nd_log-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
30 changes: 21 additions & 9 deletions src/libnetdata/log/nd_log-libunwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@

#include "nd_log-internals.h"

bool nd_log_forked = false;

#ifdef HAVE_LIBUNWIND
#include <libunwind.h>

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;

Expand All @@ -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;
Expand All @@ -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, "<unknown>");
}
}

in_stack_trace = false;
cleanup:
in_stack_trace = false; // Ensure the flag is reset
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions src/libnetdata/spawn_server/spawn_server_nofork.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit 8e127e7

Please sign in to comment.