Skip to content

Commit e6e9c58

Browse files
committed
Fix all memory leaks + Docker test infra gaps
Leaks fixed (5506 bytes → 0): - sqlite3_open_v2 allocates handle even on CANTOPEN — must call sqlite3_close before freeing struct (4x 792 bytes, 32 indirect) - graph_buffer node_by_id: reuse existing heap key on hash table replace to avoid leak (2 bytes) Docker test infrastructure: - python3 (full) instead of python3-minimal (missing json module) - git installed (19 tests were silently skipped) - sqlite3_close_v2 + sqlite3_shutdown at test exit
1 parent b7e076c commit e6e9c58

File tree

6 files changed

+26
-42
lines changed

6 files changed

+26
-42
lines changed

src/graph_buffer/graph_buffer.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,14 @@ int64_t cbm_gbuf_upsert_node(cbm_gbuf_t *gb, const char *label, const char *name
335335

336336
char id_buf[32];
337337
make_id_key(id_buf, sizeof(id_buf), id);
338-
cbm_ht_set(gb->node_by_id, strdup(id_buf), node);
338+
/* Check if key exists — if so, reuse old heap key to avoid leak.
339+
* cbm_ht_set replaces key pointer, leaking old strdup'd key. */
340+
const char *existing_key = cbm_ht_get_key(gb->node_by_id, id_buf);
341+
if (existing_key) {
342+
cbm_ht_set(gb->node_by_id, existing_key, node);
343+
} else {
344+
cbm_ht_set(gb->node_by_id, strdup(id_buf), node);
345+
}
339346

340347
/* Secondary indexes */
341348
node_ptr_array_t *by_label = get_or_create_node_array(gb->nodes_by_label, label ? label : "");
@@ -771,7 +778,12 @@ int cbm_gbuf_merge(cbm_gbuf_t *dst, cbm_gbuf_t *src) {
771778
cbm_ht_set(dst->node_by_qn, node->qualified_name, node);
772779
char id_buf[32];
773780
make_id_key(id_buf, sizeof(id_buf), node->id);
774-
cbm_ht_set(dst->node_by_id, strdup(id_buf), node);
781+
const char *old_id_key = cbm_ht_get_key(dst->node_by_id, id_buf);
782+
if (old_id_key) {
783+
cbm_ht_set(dst->node_by_id, old_id_key, node);
784+
} else {
785+
cbm_ht_set(dst->node_by_id, strdup(id_buf), node);
786+
}
775787

776788
/* Secondary indexes */
777789
node_ptr_array_t *by_label =

src/store/store.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ cbm_store_t *cbm_store_open_path_query(const char *db_path) {
378378
/* Open read-write but do NOT create — returns SQLITE_CANTOPEN if absent. */
379379
int rc = sqlite3_open_v2(db_path, &s->db, SQLITE_OPEN_READWRITE, NULL);
380380
if (rc != SQLITE_OK) {
381-
/* File does not exist or cannot be opened — return NULL without creating. */
381+
/* sqlite3_open_v2 allocates a handle even on failure — must close it. */
382+
sqlite3_close(s->db);
382383
free(s);
383384
return NULL;
384385
}
@@ -513,7 +514,9 @@ void cbm_store_close(cbm_store_t *s) {
513514
finalize_stmt(&s->stmt_delete_file_hash);
514515
finalize_stmt(&s->stmt_delete_file_hashes);
515516

516-
sqlite3_close(s->db);
517+
/* Use sqlite3_close_v2 — auto-deallocates when last statement finalizes.
518+
* Prevents ASan false-positive leaks from sqlite3 internal state. */
519+
sqlite3_close_v2(s->db);
517520
free((void *)s->db_path);
518521
free(s);
519522
}

src/ui/embedded_assets.c

Lines changed: 0 additions & 36 deletions
This file was deleted.

test-infrastructure/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
1313
gcc g++ make \
1414
zlib1g-dev \
1515
pkg-config \
16-
python3-minimal \
16+
python3 \
17+
git \
1718
&& rm -rf /var/lib/apt/lists/*
1819

1920
WORKDIR /src

tests/test_arena.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ TEST(arena_strndup_len_exceeds_string) {
308308
TEST(arena_sprintf_empty_format) {
309309
CBMArena a;
310310
cbm_arena_init(&a);
311-
char *s = cbm_arena_sprintf(&a, "");
311+
/* Use "%s" with empty string — GCC rejects literal "" as format (-Wformat-zero-length) */
312+
char *s = cbm_arena_sprintf(&a, "%s", "");
312313
ASSERT_NOT_NULL(s);
313314
ASSERT_STR_EQ(s, "");
314315
ASSERT_EQ(strlen(s), 0);

tests/test_main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ int tf_fail_count = 0;
99
int tf_skip_count = 0;
1010

1111
#include "test_framework.h"
12+
#include <sqlite3.h>
1213

1314
/* Forward declarations of suite functions */
1415
extern void suite_arena(void);
@@ -147,5 +148,7 @@ int main(void) {
147148
/* Integration (end-to-end) */
148149
RUN_SUITE(integration);
149150

151+
/* Release sqlite3 internal caches so ASan doesn't report them as leaks */
152+
sqlite3_shutdown();
150153
TEST_SUMMARY();
151154
}

0 commit comments

Comments
 (0)