From 355d010ddf1dac50fe72ab36fbfdddef2a60a379 Mon Sep 17 00:00:00 2001 From: Ryan Patterson Date: Tue, 16 Jun 2026 20:22:33 +0800 Subject: [PATCH] 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 --- src/nvim/lua/treesitter.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 03f472dd51..dae9e88ee6 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -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