Release memory on shutdown - detect invalid extent in journal files (#19861)
* Release all memory for metasync thread * Cleanup * Validate extent index in journal entries to prevent invalid access * Proper free * Improve error logging for invalid extent index in journal file
Stelios Fragkakis committed
Mar 14, 2025 at 23:53 UTC
fc83a2e9e7503afa4758d64315862a5cd6f8d34a
2 files changed
+21
-6
src/database/engine/pagecache.c
+8
@@ -530,6 +530,7 @@ static ALWAYS_INLINE_HOT size_t get_page_list_from_journal_v2(struct rrdengine_i
530
struct journal_page_header *page_list_header = (struct journal_page_header *) ((uint8_t *) j2_header + uuid_entry->page_offset);
531
struct journal_page_list *page_list = (struct journal_page_list *)((uint8_t *) page_list_header + sizeof(*page_list_header));
532
struct journal_extent_list *extent_list = (void *)((uint8_t *)j2_header + j2_header->extent_offset);
533
+ uint32_t extent_entries = j2_header->extent_count;
534
uint32_t uuid_page_entries = page_list_header->entries;
535
536
for (uint32_t index = 0; index < uuid_page_entries; index++) {
@@ -545,6 +546,13 @@ static ALWAYS_INLINE_HOT size_t get_page_list_from_journal_v2(struct rrdengine_i
546
if(prc == PAGE_IS_IN_THE_FUTURE)
547
break;
548
549
+ // Make sure index is valid for this file
550
+ if (page_entry_in_journal->extent_index > extent_entries) {
551
+ nd_log_limit_static_thread_var(erl, 60, 0);
552
+ nd_log_limit(&erl, NDLS_DAEMON, NDLP_ERR, "DBENGINE: Invalid extent index in journalfile %u", datafile->fileno);
553
+ break;
554
+ }
555
+
556
uint32_t page_update_every_s = page_entry_in_journal->update_every_s;
557
size_t page_length = page_entry_in_journal->page_length;
558
src/database/sqlite/sqlite_metadata.c
+13
-6
@@ -2417,6 +2417,15 @@ static void start_metadata_hosts(uv_work_t *req)
2417
worker_is_idle();
2418
}
2419
2420
+static void close_callback(uv_handle_t *handle, void *data __maybe_unused)
2421
+{
2422
+ if (handle->type == UV_TIMER) {
2423
+ uv_timer_stop((uv_timer_t *)handle);
2424
+ }
2425
+
2426
+ uv_close(handle, NULL); // Automatically close and free the handle
2427
+}
2428
+
2429
static void metadata_event_loop(void *arg)
2430
{
2431
worker_register("METASYNC");
@@ -2430,7 +2439,6 @@ static void metadata_event_loop(void *arg)
2439
worker_register_job_name(METADATA_DEL_HOST_AE, "delete host alert entry");
2440
2441
int ret;
2433
- uv_loop_t *loop;
2442
unsigned cmd_batch_size;
2443
struct metadata_wc *wc = arg;
2444
enum metadata_opcode opcode;
@@ -2438,12 +2446,13 @@ static void metadata_event_loop(void *arg)
2446
wc->ar = aral_by_size_acquire(sizeof(struct metadata_cmd));
2447
2448
uv_thread_set_name_np("METASYNC");
2441
- loop = wc->loop = mallocz(sizeof(uv_loop_t));
2449
+ uv_loop_t *loop = wc->loop = mallocz(sizeof(uv_loop_t));
2450
ret = uv_loop_init(loop);
2451
if (ret) {
2452
netdata_log_error("uv_loop_init(): %s", uv_strerror(ret));
2453
goto error_after_loop_init;
2454
}
2455
+
2456
loop->data = wc;
2457
2458
ret = uv_async_init(wc->loop, &wc->async, async_cb);
@@ -2619,17 +2628,15 @@ static void metadata_event_loop(void *arg)
2628
} while (opcode != METADATA_DATABASE_NOOP);
2629
}
2630
2622
- if (!uv_timer_stop(&wc->timer_req))
2623
- uv_close((uv_handle_t *)&wc->timer_req, NULL);
2631
+ uv_walk(loop, (uv_walk_cb) close_callback, NULL);
2632
+ uv_run(loop, UV_RUN_NOWAIT);
2633
2625
- uv_close((uv_handle_t *)&wc->async, NULL);
2634
int rc;
2635
do {
2636
rc = uv_loop_close(loop);
2637
} while (rc != UV_EBUSY);
2638
2639
buffer_free(work_buffer);
2632
- freez(loop);
2640
worker_unregister();
2641
2642
nd_log(NDLS_DAEMON, NDLP_DEBUG, "Shutting down metadata thread");