@cryptotaxi247 / netdata-1 / commits / 73daaf8ea

Help finding leaks and running valgrind (#19806)

* disable signal handler when compiling with -DFSANITIZE=1 * no need for packed ; valgrind complains about it * help the IDE detect use after free, when removing receiver and senders * disable function inlining when compiling with -DFSANITIZE

Costa Tsaousis committed Mar 8, 2025 at 18:31 UTC 73daaf8ea9084a1e904bc110b261259379101148
6 files changed +42 -9
src/daemon/signal-handler.c
+9
@@ -87,6 +87,9 @@ static void posix_unmask_my_signals(void) {
87 }
88
89 void nd_initialize_signals(void) {
90 +#if defined(FSANITIZE)
91 + ;
92 +#else
93 signals_block_all_except_deadly();
94
95 // Catch signals which we want to use
@@ -109,6 +112,7 @@ void nd_initialize_signals(void) {
112 if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1)
113 netdata_log_error("SIGNAL: Failed to change signal handler for: %s", signals_waiting[i].name);
114 }
115 +#endif
116 }
117
118 static void process_triggered_signals(void) {
@@ -161,6 +165,10 @@ static void process_triggered_signals(void) {
165 }
166
167 void nd_process_signals(void) {
168 +#if defined(FSANITIZE)
169 + while(true)
170 + pause();
171 +#else
172 posix_unmask_my_signals();
173 const usec_t save_every_ut = 15 * 60 * USEC_PER_SEC;
174 usec_t last_update_mt = now_monotonic_usec();
@@ -175,4 +183,5 @@ void nd_process_signals(void) {
183 poll(NULL, 0, 13 * MSEC_PER_SEC + 379);
184 process_triggered_signals();
185 }
186 +#endif
187 }
src/libnetdata/common.h
+1 -1
@@ -335,7 +335,7 @@ typedef uint32_t uid_t;
335
336 #define UNUSED(x) (void)(x)
337
338 -#ifdef __GNUC__
338 +#if defined(__GNUC__) && !defined(FSANITIZE)
339 #define UNUSED_FUNCTION(x) __attribute__((unused)) UNUSED_##x
340 #define ALWAYS_INLINE_ONLY __attribute__((always_inline))
341 #define ALWAYS_INLINE inline __attribute__((always_inline)) // Forces inlining
src/libnetdata/signals/signals.c
+8
@@ -3,12 +3,16 @@
3 #include "../libnetdata.h"
4
5 void signals_block_all(void) {
6 +#if defined(FSANITIZE)
7 + ;
8 +#else
9 sigset_t sigset;
10 sigfillset(&sigset);
11
12 if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) != 0)
13 nd_log(NDLS_DAEMON, NDLP_ERR,
14 "SIGNALS: cannot apply the default mask for signals");
15 +#endif
16 }
17
18 void signals_unblock_one(int signo) {
@@ -35,8 +39,12 @@ void signals_unblock(int signals[], size_t count) {
39 }
40
41 void signals_unblock_deadly(void) {
42 +#if defined(FSANITIZE)
43 + ;
44 +#else
45 int deadly_signals[] = {SIGBUS, SIGSEGV, SIGFPE, SIGILL, SIGABRT};
46 signals_unblock(deadly_signals, _countof(deadly_signals));
47 +#endif
48 }
49
50 void signals_block_all_except_deadly(void) {
src/libnetdata/spawn_server/spawn_server_nofork.c
+1 -1
@@ -119,7 +119,7 @@ static const char** argv_decode(const char *buffer, size_t size) {
119 // --------------------------------------------------------------------------------------------------------------------
120 // status reports
121
122 -typedef enum __attribute__((packed)) {
122 +typedef enum {
123 STATUS_REPORT_NONE = 0,
124 STATUS_REPORT_STARTED,
125 STATUS_REPORT_FAILED,
src/streaming/stream-receiver.c
+12 -3
@@ -65,7 +65,13 @@ void stream_receiver_log_payload(struct receiver_state *rpt, const char *payload
65 }
66 #endif
67
68 -static void stream_receiver_remove(struct stream_thread *sth, struct receiver_state *rpt, STREAM_HANDSHAKE reason);
68 +// help the IDE identify use after free
69 +#define stream_receiver_remove(sth, rpt, reason) do { \
70 + stream_receiver_remove_internal(sth, rpt, reason); \
71 + (rpt) = NULL; \
72 +} while(0)
73 +
74 +static void stream_receiver_remove_internal(struct stream_thread *sth, struct receiver_state *rpt, STREAM_HANDSHAKE reason);
75
76 // When a child disconnects this is the maximum we will wait
77 // before we update the cloud that the child is offline
@@ -523,7 +529,7 @@ void stream_receiver_move_entire_queue_to_running_unsafe(struct stream_thread *s
529 }
530 }
531
526 -static void stream_receiver_remove(struct stream_thread *sth, struct receiver_state *rpt, STREAM_HANDSHAKE reason) {
532 +static void stream_receiver_remove_internal(struct stream_thread *sth, struct receiver_state *rpt, STREAM_HANDSHAKE reason) {
533 internal_fatal(sth->tid != gettid_cached(), "Function %s() should only be used by the dispatcher thread", __FUNCTION__ );
534
535 receiver_set_exit_reason(rpt, reason, false);
@@ -540,7 +546,9 @@ static void stream_receiver_remove(struct stream_thread *sth, struct receiver_st
546 ND_LOG_STACK_PUSH(lgs);
547
548 PARSER *parser = __atomic_load_n(&rpt->thread.parser, __ATOMIC_RELAXED);
543 - size_t count = parser ? parser->user.data_collections_count : 0;
549 + size_t count = 0;
550 + if(parser)
551 + count = parser->user.data_collections_count;
552
553 errno_clear();
554 nd_log(NDLS_DAEMON, NDLP_ERR,
@@ -850,6 +858,7 @@ bool stream_receiver_receive_data(struct stream_thread *sth, struct receiver_sta
858 stream_handshake_error_to_string(reason), rpt->sock.fd);
859
860 stream_receiver_remove(sth, rpt, reason);
861 + break;
862 }
863 else if(status == EVLOOP_STATUS_CONTINUE && process_opcodes && stream_thread_process_opcodes(sth, &rpt->thread.meta))
864 status = EVLOOP_STATUS_OPCODE_ON_ME;
src/streaming/stream-sender.c
+11 -4
@@ -4,7 +4,13 @@
4 #include "stream-sender-internals.h"
5 #include "stream-replication-sender.h"
6
7 -static void stream_sender_move_running_to_connector_or_remove(struct stream_thread *sth, struct sender_state *s, STREAM_HANDSHAKE reason, STREAM_HANDSHAKE receiver_reason, bool reconnect);
7 +// help the IDE detect use after free
8 +#define stream_sender_move_running_to_connector_or_remove(sth, s, reason, receiver_reason, reconnect) do { \
9 + stream_sender_move_running_to_connector_or_remove_internal(sth, s, reason, receiver_reason, reconnect); \
10 + (s) = NULL; \
11 +} while(0)
12 +
13 +static void stream_sender_move_running_to_connector_or_remove_internal(struct stream_thread *sth, struct sender_state *s, STREAM_HANDSHAKE reason, STREAM_HANDSHAKE receiver_reason, bool reconnect);
14
15 // --------------------------------------------------------------------------------------------------------------------
16
@@ -404,7 +410,7 @@ static void stream_sender_log_disconnection(struct stream_thread *sth, struct se
410 sth->id, rrdhost_hostname(s->host), s->remote_ip, stream_handshake_error_to_string(reason));
411 }
412
407 -static void stream_sender_move_running_to_connector_or_remove(struct stream_thread *sth, struct sender_state *s, STREAM_HANDSHAKE reason, STREAM_HANDSHAKE receiver_reason, bool reconnect) {
413 +static void stream_sender_move_running_to_connector_or_remove_internal(struct stream_thread *sth, struct sender_state *s, STREAM_HANDSHAKE reason, STREAM_HANDSHAKE receiver_reason, bool reconnect) {
414 internal_fatal(sth->tid != gettid_cached(), "Function %s() should only be used by the dispatcher thread", __FUNCTION__ );
415
416 ND_LOG_STACK lgs[] = {
@@ -714,6 +720,7 @@ bool stream_sender_send_data(struct stream_thread *sth, struct sender_state *s,
720 // this is not executed from the opcode handling mechanism
721 // so we can safely remove the sender
722 stream_sender_move_running_to_connector_or_remove(sth, s, reason, 0, true);
723 + break;
724 }
725 else {
726 // protection against this case:
@@ -783,8 +790,8 @@ bool stream_sender_receive_data(struct stream_thread *sth, struct sender_state *
790 "STREAM SND[%zu] '%s' [to %s]: %s (fd %d) - restarting sender connection.",
791 sth->id, rrdhost_hostname(s->host), s->remote_ip, disconnect_reason, s->sock.fd);
792
786 - stream_sender_move_running_to_connector_or_remove(
787 - sth, s, reason, 0, true);
793 + stream_sender_move_running_to_connector_or_remove(sth, s, reason, 0, true);
794 + break;
795 }
796 else if(status == EVLOOP_STATUS_CONTINUE && process_opcodes && stream_thread_process_opcodes(sth, &s->thread.meta))
797 status = EVLOOP_STATUS_OPCODE_ON_ME;