Skip to content

Commit 82d5c84

Browse files
committed
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.
1 parent 297003a commit 82d5c84

2 files changed

Lines changed: 11 additions & 0 deletions

File tree

src/pipeline/pass_definitions.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
333333
/* Ensure extraction library is initialized */
334334
cbm_init();
335335

336+
/* Defensive: a prior pipeline run may have left a thread-local parser whose
337+
* lexer holds pointers into a slab that has since been reclaimed. Drop it
338+
* here so the first cbm_extract_file below recreates a fresh parser. */
339+
cbm_destroy_thread_parser();
340+
336341
int total_defs = 0;
337342
int total_calls = 0;
338343
int total_imports = 0;

src/pipeline/pass_parallel.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,6 +2128,12 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
21282128
}
21292129
}
21302130
free(filtered);
2131+
/* Contract: cbm_slab_reclaim() requires the thread parser to be
2132+
* destroyed first; otherwise its lexer holds slab pointers
2133+
* (lexer.included_ranges) that get freed underneath it, causing
2134+
* a heap-use-after-free on the next ts_lexer_goto. The next
2135+
* cbm_extract_file on this thread will recreate the parser. */
2136+
cbm_destroy_thread_parser();
21312137
cbm_slab_reclaim();
21322138
uint64_t lsp_elapsed_ns = extract_now_ns() - lsp_t0;
21332139
atomic_fetch_add_explicit(&rc->time_ns_cross_lsp, lsp_elapsed_ns,

0 commit comments

Comments
 (0)