@cryptotaxi247 / netdata-1 / commits / 8e127e755

disable libunwind on forked children (#19374)

libunwind does not work well after fork, so we disable stack traces on forked processes

Costa Tsaousis committed Jan 10, 2025 at 16:42 UTC 8e127e75527a02c2b3854f94b419cf8138a378cf
4 files changed +27 -9
src/libnetdata/log/nd_log-init.c
+2
@@ -274,6 +274,8 @@ int nd_log_systemd_journal_fd(void) {
274 }
275
276 void nd_log_reopen_log_files_for_spawn_server(const char *name) {
277 + nd_log_forked = true;
278 +
279 gettid_uncached();
280
281 if(nd_log.syslog.initialized) {
src/libnetdata/log/nd_log-internals.h
+2
@@ -196,6 +196,8 @@ struct log_field;
196 const char *errno_annotator(struct log_field *lf);
197 const char *priority_annotator(struct log_field *lf);
198 const char *timestamp_usec_annotator(struct log_field *lf);
199 +
200 +extern bool nd_log_forked;
201 bool stack_trace_formatter(BUFFER *wb, void *data);
202
203 #if defined(OS_WINDOWS)
src/libnetdata/log/nd_log-libunwind.c
+21 -9
@@ -2,15 +2,25 @@
2
3 #include "nd_log-internals.h"
4
5 +bool nd_log_forked = false;
6 +
7 #ifdef HAVE_LIBUNWIND
8 #include <libunwind.h>
9
10 bool stack_trace_formatter(BUFFER *wb, void *data __maybe_unused) {
11 static __thread bool in_stack_trace = false;
12
11 - // Prevent recursion
12 - if(in_stack_trace)
13 - return buffer_strcat(wb, "stack trace recursion detected"), true;
13 + if (nd_log_forked) {
14 + // libunwind freezes in forked children
15 + buffer_strcat(wb, "stack trace after fork is disabled");
16 + return true;
17 + }
18 +
19 + if (in_stack_trace) {
20 + // Prevent recursion
21 + buffer_strcat(wb, "stack trace recursion detected");
22 + return true;
23 + }
24
25 in_stack_trace = true;
26
@@ -23,9 +33,10 @@ bool stack_trace_formatter(BUFFER *wb, void *data __maybe_unused) {
33 unw_init_local(&cursor, &context);
34
35 // Skip first 3 frames (our logging infrastructure)
26 - unw_step(&cursor);
27 - unw_step(&cursor);
28 - unw_step(&cursor);
36 + for (int i = 0; i < 3; i++) {
37 + if (unw_step(&cursor) <= 0)
38 + goto cleanup; // Ensure proper cleanup if unwinding fails early
39 + }
40
41 while (unw_step(&cursor) > 0) {
42 unw_word_t offset, pc;
@@ -37,17 +48,18 @@ bool stack_trace_formatter(BUFFER *wb, void *data __maybe_unused) {
48
49 const char *name = sym;
50 if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
40 - if(frames++) buffer_strcat(wb, "\n");
51 + if (frames++) buffer_strcat(wb, "\n");
52 buffer_sprintf(wb, "%s+0x%lx", name, (unsigned long)offset);
53 }
54 else {
44 - if(frames++)
55 + if (frames++)
56 buffer_strcat(wb, "\n");
57 buffer_strcat(wb, "<unknown>");
58 }
59 }
60
50 - in_stack_trace = false;
61 +cleanup:
62 + in_stack_trace = false; // Ensure the flag is reset
63 return true;
64 }
65
src/libnetdata/spawn_server/spawn_server_nofork.c
+2
@@ -1210,6 +1210,8 @@ int spawn_server_exec_kill(SPAWN_SERVER *server, SPAWN_INSTANCE *instance, int t
1210 }
1211
1212 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) {
1213 + if(!server) return NULL;
1214 +
1215 int pipe_stdin[2] = { -1, -1 }, pipe_stdout[2] = { -1, -1 };
1216
1217 SPAWN_INSTANCE *instance = callocz(1, sizeof(SPAWN_INSTANCE));