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;