mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(parallel): destroy thread parser before slab reclaim in LSP-cross loop
The LSP-cross loop in parallel_resolve called cbm_slab_reclaim() without first destroying the thread-local tree-sitter parser, violating the documented slab contract. The parser's lexer holds slab-allocated state (notably lexer.included_ranges, a 24-byte allocation that lands in the ≤64B slab bucket); reclaiming the slab leaves that pointer dangling. Workers don't trip on it because they don't reparse afterward, but the main thread participates in cbm_parallel_for and any later cbm_extract_file on the main thread — including the sequential pass_definitions in the incremental pipeline — hits a heap-use-after-free in ts_lexer_goto on macOS-ASan. Two-part fix: - pass_parallel.c: destroy the thread parser before cbm_slab_reclaim() in the per-file LSP-cross loop, matching the worker extract loop. - pass_definitions.c: defensively drop the thread parser at pass entry so the incremental sequential path cannot inherit stale state from any prior run.
This commit is contained in:
1 parent
297003aab4
commit
82d5c841e6
2 files changed
+11
No files matched your search
@@ -333,6 +333,11 @@ int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
|
||||
/* Ensure extraction library is initialized */
|
||||
cbm_init();
|
||||
|
||||
/* Defensive: a prior pipeline run may have left a thread-local parser whose
|
||||
* lexer holds pointers into a slab that has since been reclaimed. Drop it
|
||||
* here so the first cbm_extract_file below recreates a fresh parser. */
|
||||
cbm_destroy_thread_parser();
|
||||
|
||||
int total_defs = 0;
|
||||
int total_calls = 0;
|
||||
int total_imports = 0;
|
||||
|
||||
@@ -2128,6 +2128,12 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
|
||||
}
|
||||
}
|
||||
free(filtered);
|
||||
/* Contract: cbm_slab_reclaim() requires the thread parser to be
|
||||
* destroyed first; otherwise its lexer holds slab pointers
|
||||
* (lexer.included_ranges) that get freed underneath it, causing
|
||||
* a heap-use-after-free on the next ts_lexer_goto. The next
|
||||
* cbm_extract_file on this thread will recreate the parser. */
|
||||
cbm_destroy_thread_parser();
|
||||
cbm_slab_reclaim();
|
||||
uint64_t lsp_elapsed_ns = extract_now_ns() - lsp_t0;
|
||||
atomic_fetch_add_explicit(&rc->time_ns_cross_lsp, lsp_elapsed_ns,
|
||||
|
||||
Reference in new issue
Block a user