fix(wasm): fix alias map size computation

This fixes a crash where parsing with certain languages can lead to a crash due to how the alias map was allocated and laid out in wasm memory
This commit is contained in:
Nia 2025-09-19 00:34:27 +02:00 committed by GitHub
parent f222db57ce
commit f09dc3cf46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 80 additions and 26 deletions

View file

@ -23,6 +23,9 @@ static TEST_LOADER: LazyLock<Loader> = LazyLock::new(|| {
loader
});
#[cfg(feature = "wasm")]
pub static ENGINE: LazyLock<tree_sitter::wasmtime::Engine> = LazyLock::new(Default::default);
pub fn test_loader() -> &'static Loader {
&TEST_LOADER
}
@ -43,10 +46,19 @@ pub fn get_language(name: &str) -> Language {
}
pub fn get_test_fixture_language(name: &str) -> Language {
get_test_fixture_language_internal(name, false)
}
#[cfg(feature = "wasm")]
pub fn get_test_fixture_language_wasm(name: &str) -> Language {
get_test_fixture_language_internal(name, true)
}
fn get_test_fixture_language_internal(name: &str, wasm: bool) -> Language {
let grammar_dir_path = fixtures_dir().join("test_grammars").join(name);
let grammar_json = load_grammar_file(&grammar_dir_path.join("grammar.js"), None).unwrap();
let (parser_name, parser_code) = generate_parser(&grammar_json).unwrap();
get_test_language(&parser_name, &parser_code, Some(&grammar_dir_path))
get_test_language_internal(&parser_name, &parser_code, Some(&grammar_dir_path), wasm)
}
pub fn get_language_queries_path(language_name: &str) -> PathBuf {
@ -87,6 +99,15 @@ pub fn get_tags_config(language_name: &str) -> TagsConfiguration {
}
pub fn get_test_language(name: &str, parser_code: &str, path: Option<&Path>) -> Language {
get_test_language_internal(name, parser_code, path, false)
}
fn get_test_language_internal(
name: &str,
parser_code: &str,
path: Option<&Path>,
wasm: bool,
) -> Language {
let src_dir = scratch_dir().join("src").join(name);
fs::create_dir_all(&src_dir).unwrap();
@ -136,5 +157,21 @@ pub fn get_test_language(name: &str, parser_code: &str, path: Option<&Path>) ->
config.header_paths = vec![&HEADER_DIR];
config.name = name.to_string();
TEST_LOADER.load_language_at_path_with_name(config).unwrap()
if wasm {
#[cfg(feature = "wasm")]
{
let mut loader = Loader::with_parser_lib_path(SCRATCH_DIR.clone());
loader.use_wasm(&ENGINE);
if env::var("TREE_SITTER_GRAMMAR_DEBUG").is_ok() {
loader.debug_build(true);
}
loader.load_language_at_path_with_name(config).unwrap()
}
#[cfg(not(feature = "wasm"))]
{
unimplemented!("Wasm feature is not enabled")
}
} else {
TEST_LOADER.load_language_at_path_with_name(config).unwrap()
}
}

View file

@ -1,14 +1,13 @@
use std::{fs, sync::LazyLock};
use std::fs;
use streaming_iterator::StreamingIterator;
use tree_sitter::{
wasmtime::Engine, Parser, Query, QueryCursor, WasmError, WasmErrorKind, WasmStore,
use tree_sitter::{Parser, Query, QueryCursor, WasmError, WasmErrorKind, WasmStore};
use crate::tests::helpers::{
allocations,
fixtures::{get_test_fixture_language_wasm, ENGINE, WASM_DIR},
};
use crate::tests::helpers::{allocations, fixtures::WASM_DIR};
static ENGINE: LazyLock<Engine> = LazyLock::new(Engine::default);
#[test]
fn test_wasm_stdlib_symbols() {
let symbols = tree_sitter::wasm_stdlib_symbols().collect::<Vec<_>>();
@ -92,6 +91,33 @@ fn test_load_wasm_javascript_language() {
});
}
#[test]
fn test_load_wasm_python_language() {
allocations::record(|| {
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm = fs::read(WASM_DIR.join("tree-sitter-python.wasm")).unwrap();
let language = store.load_language("python", &wasm).unwrap();
parser.set_wasm_store(store).unwrap();
parser.set_language(&language).unwrap();
let tree = parser.parse("a = b\nc = d", None).unwrap();
assert_eq!(tree.root_node().to_sexp(), "(module (expression_statement (assignment left: (identifier) right: (identifier))) (expression_statement (assignment left: (identifier) right: (identifier))))");
});
}
#[test]
fn test_load_fixture_language_wasm() {
allocations::record(|| {
let store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let language = get_test_fixture_language_wasm("epsilon_external_tokens");
parser.set_wasm_store(store).unwrap();
parser.set_language(&language).unwrap();
let tree = parser.parse("hello", None).unwrap();
assert_eq!(tree.root_node().to_sexp(), "(document (zero_width))");
});
}
#[test]
fn test_load_multiple_wasm_languages() {
allocations::record(|| {