@cryptotaxi247 / netdata-1 / commits / 8e49531c6

Fix memory-safety and correctness bugs surfaced by Coverity audit (part 8) (#22293)

daemon: free removed stale nodes outside rrd lock Coverity CID 442107 (SLEEP): remove-stale-node held the global RRD write lock while freeing a host. Unlink the host under the lock, then run teardown/freeing outside the lock so logging and stream shutdown waits do not block global RRD progress.

Costa Tsaousis committed Apr 27, 2026 at 20:24 UTC 8e49531c6f3d7b4eee6be62c89dc245573104e5a
3 files changed +23 -15
src/daemon/commands.c
+1 -3
@@ -389,9 +389,7 @@ static int remove_ephemeral_host(BUFFER *wb, RRDHOST *host, bool report_error, b
389 host->node_id = UUID_ZERO;
390 buffer_sprintf(wb, "Node '%s' (machine guid: %s) has been unregistered",
391 rrdhost_hostname(host), host->machine_guid);
392 - rrd_wrlock();
393 - rrdhost_free___while_having_rrd_wrlock(host);
394 - rrd_wrunlock();
392 + rrdhost_free___without_having_rrd_wrlock(host);
393 return 1;
394 }
395
src/database/rrdhost.c
+21 -12
@@ -800,23 +800,15 @@ void rrdhost_cleanup_data_collection_and_health(RRDHOST *host) {
800 rrdhost_hostname(host));
801 }
802
803 -void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host) {
804 - if(!host) return;
805 -
806 - nd_log(NDLS_DAEMON, NDLP_DEBUG,
807 - "RRD: 'host:%s' freeing memory...",
808 - rrdhost_hostname(host));
809 -
810 - // ------------------------------------------------------------------------
811 - // first remove it from the indexes, so that it will not be discoverable
812 -
803 +static void rrdhost_unlink___while_having_rrd_wrlock(RRDHOST *host) {
804 + // Remove it from the indexes first, so blocking teardown cannot rediscover it.
805 rrdhost_index_del_by_guid(host);
806
807 if (host->prev)
808 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(localhost, host, prev, next);
809 +}
810
818 - // ------------------------------------------------------------------------
819 -
811 +static void rrdhost_free_unlinked(RRDHOST *host) {
812 rrdhost_cleanup_data_collection_and_health(host);
813
814 // ------------------------------------------------------------------------
@@ -847,6 +839,23 @@ void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host) {
839 freez(host);
840 }
841
842 +void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host) {
843 + if(!host) return;
844 +
845 + rrdhost_unlink___while_having_rrd_wrlock(host);
846 + rrdhost_free_unlinked(host);
847 +}
848 +
849 +void rrdhost_free___without_having_rrd_wrlock(RRDHOST *host) {
850 + if(!host) return;
851 +
852 + rrd_wrlock();
853 + rrdhost_unlink___while_having_rrd_wrlock(host);
854 + rrd_wrunlock();
855 +
856 + rrdhost_free_unlinked(host);
857 +}
858 +
859 void rrdhost_free_all(void) {
860 rrd_wrlock();
861
src/database/rrdhost.h
+1
@@ -456,6 +456,7 @@ RRDHOST *rrdhost_find_or_create(
456 void rrdhost_free_all(void);
457
458 void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host);
459 +void rrdhost_free___without_having_rrd_wrlock(RRDHOST *host);
460 void rrdhost_cleanup_data_collection_and_health(RRDHOST *host);
461
462 bool rrdhost_should_be_cleaned_up(RRDHOST *host, RRDHOST *protected_host, time_t now_s);