Fix all memory leaks, vendor sqlite3, add Docker test infrastructure

Leak fixes (13 sources, 1.4MB → 0 bytes):
- Cypher: free col_names after rb_set_columns, free rejected inline
  prop nodes, store WITH aliases in qualified_name for auto-cleanup
- Store: add cbm_project_free_fields, fix find_node_ids_by_qns leak
- Graph buffer: free strdup'd hash keys during delete operations
- SQL scanner: free old start_tag before reassignment in deserialize

Platform independence:
- Vendor sqlite3 amalgamation (3.49.1) — eliminates system libsqlite3
  dependency, enables full ASan/LeakSanitizer instrumentation
- Add -I for vendored tree-sitter unicode headers — eliminates hidden
  dependency on system libicu-dev
- Add test-infrastructure/ with Docker Compose for local GCC+ASan
  testing that mirrors CI exactly
This commit is contained in:
Martin Vogel
2026-03-18 16:28:27 +01:00
parent bc66541765
commit a1d849aaaa
15 changed files with 261887 additions and 530 deletions
+12 -7
View File
@@ -422,8 +422,10 @@ int cbm_gbuf_delete_by_label(cbm_gbuf_t *gb, const char *label) {
/* Remove from primary indexes */
cbm_ht_delete(gb->node_by_qn, n->qualified_name);
void *removed_key = cbm_ht_delete(gb->node_by_id, id_buf);
(void)removed_key;
/* Free the strdup'd key stored in node_by_id (get before delete) */
const char *stored_key = cbm_ht_get_key(gb->node_by_id, id_buf);
cbm_ht_delete(gb->node_by_id, id_buf);
free((void *)stored_key);
}
/* Clear the label array */
@@ -442,11 +444,12 @@ int cbm_gbuf_delete_by_label(cbm_gbuf_t *gb, const char *label) {
make_id_key(tgt_id, sizeof(tgt_id), e->target_id);
if (cbm_ht_get(deleted_set, src_id) || cbm_ht_get(deleted_set, tgt_id)) {
/* Remove from edge dedup index */
/* Remove from edge dedup index (free the strdup'd key) */
char key[EDGE_KEY_BUF];
make_edge_key(key, sizeof(key), e->source_id, e->target_id, e->type);
void *k = cbm_ht_delete(gb->edge_by_key, key);
(void)k;
const char *ekey = cbm_ht_get_key(gb->edge_by_key, key);
cbm_ht_delete(gb->edge_by_key, key);
free((void *)ekey);
/* Remove from secondary indexes incrementally */
make_src_type_key(key, sizeof(key), e->source_id, e->type);
@@ -490,6 +493,7 @@ int cbm_gbuf_delete_by_label(cbm_gbuf_t *gb, const char *label) {
}
gb->edges.count = write_idx;
cbm_ht_foreach(deleted_set, free_key_only, NULL);
cbm_ht_free(deleted_set);
return 0;
}
@@ -636,8 +640,9 @@ int cbm_gbuf_delete_edges_by_type(cbm_gbuf_t *gb, const char *type) {
if (strcmp(e->type, type) == 0) {
char key[EDGE_KEY_BUF];
make_edge_key(key, sizeof(key), e->source_id, e->target_id, e->type);
void *k = cbm_ht_delete(gb->edge_by_key, key);
(void)k;
const char *ekey = cbm_ht_get_key(gb->edge_by_key, key);
cbm_ht_delete(gb->edge_by_key, key);
free((void *)ekey);
free_edge_strings(e);
free(e);
} else {