fix(treesitter): give each wasm parser its own TSWasmStore #40163

All wasm parsers shared a single global TSWasmStore via
ts_parser_set_wasm_store(). A TSWasmStore is owned by exactly one parser:
ts_parser_delete() frees it through ts_wasm_store_delete(). So the first
wasm parser collected freed the shared store, leaving the global pointer
dangling, and creating the next wasm parser dereferenced freed memory in
ts_wasm_store_reset() -> wasmtime_store_context(), crashing with SIGSEGV.

Give each parser its own store via ts_wasm_store_new() instead. This is
the 1:1 store-per-parser model intended by tree-sitter (see
tree-sitter/tree-sitter#3454): the global store remains only as the
language loader, ts_parser_delete() cleanly frees each parser's own
store, and the wasm engine is shared safely because ts_wasm_store_new()
clones its engine reference internally.

AI-assisted: Claude Code
This commit is contained in:
Ryan Patterson
2026-06-16 20:22:33 +08:00
committed by GitHub
parent 823517ad1d
commit 355d010ddf

View File

@@ -384,7 +384,14 @@ static int tslua_push_parser(lua_State *L)
#ifdef HAVE_WASMTIME
if (ts_language_is_wasm(lang)) {
assert(wasmengine != NULL);
ts_parser_set_wasm_store(*parser, ts_wasmstore);
TSWasmError werr = { 0 };
TSWasmStore *store = ts_wasm_store_new(wasmengine, &werr);
if (werr.kind != TSWasmErrorKindNone) {
ts_parser_delete(*parser);
return luaL_error(L, "Failed to create WASM store: (%s) %s",
wasmerr_to_str(werr.kind), werr.message);
}
ts_parser_set_wasm_store(*parser, store);
}
#endif