fix(pipeline): release db_path/db_dir on the manifest abort paths; free the test harness cross arena

Second LSan round from the Linux leg, both verified green in the container
(532 passed, 0 failed under LSan):

- dump_and_persist_hashes' two semantic-manifest abort returns leaked BOTH of
  the function's strdups (db_path and db_dir, the latter otherwise freed only
  further down). Same ownership rule as the previous fix: every exit releases
  what the function allocated.

- test_parallel's sequential harness drives the passes directly and never
  destroyed ctx->seq_cross_arena, which the cross pass fills with the shared
  per-language registries (stdlib registrations included -- ~20MB per test).
  Production's run_sequential_pipeline destroys it after all passes; the
  harness now does the same.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-08-02 22:40:01 +02:00
1 parent 37d23d3619
commit 43e861e36a
2 files changed
+16

No files matched your search

+7
View File
@@ -1734,12 +1734,19 @@ static int dump_and_persist_hashes(cbm_pipeline_t *p, const cbm_file_hash_t *bas
if (cbm_pipeline_build_fresh_semantic_manifest(p->project_name, p->repo_path, p->mode,
&manifest, &manifest_count) != 0) {
cbm_log_error("pipeline.err", "phase", "semantic_manifest");
/* db_path and db_dir are this function's strdups; the success tail and
* the publish-failure return release them, and these two aborts must
* too -- LSan caught exactly these paths leaking both strings. */
free(db_dir);
free(db_path);
return CBM_PIPELINE_ABORT_PRESERVE_DB;
}
if (!cbm_pipeline_semantic_manifests_equal(baseline_manifest, baseline_count, manifest,
manifest_count)) {
cbm_log_warn("pipeline.abort", "reason", "semantic_inputs_changed");
cbm_pipeline_free_semantic_manifest(manifest, manifest_count);
free(db_dir);
free(db_path);
return CBM_PIPELINE_ABORT_PRESERVE_DB;
}
+9
View File
@@ -244,6 +244,15 @@ static cbm_gbuf_t *run_sequential_with_lsp_cross_and_mutator(
}
free(cache);
cbm_registry_free(reg);
/* The cross pass builds its shared registries in the caller-owned
* ctx->seq_cross_arena precisely so they outlive pass_calls; production's
* run_sequential_pipeline destroys that arena after all passes, and this
* harness must too -- LSan flagged the whole registry arena (stdlib
* registrations included) leaking per test. */
if (ctx.seq_cross_arena_live) {
cbm_arena_destroy(&ctx.seq_cross_arena);
ctx.seq_cross_arena_live = false;
}
return gbuf;
}