clone wasm store engine (#3542)

This resolves https://github.com/tree-sitter/tree-sitter/issues/3454.

This brings the usage of wasmtime::Engine in line with how wasmtime
intends it to be used. All wasmtime functions that receive an Engine
always receive an `&Engine`, never an owned `Engine`.  They are always
responsible for cloning the reference if they need it.

This brings the usage of wasmtime::Engine in line with how TSParser
treats TSLanguages: when setting a language to the parser, the parser is
responsible for cloning the reference to the TSLanguage. It is
counterintuitive for TSParser to have different behavior when receiving
wasmtime_engine_t.

C API users also expect this behavior, see "Memory Management"
[here](https://docs.wasmtime.dev/c-api/wasm_8h.html). Talking about the
C API: without this change, failing to clone the `wasmtime_engine_t`
(which, again, is never something API users need to do in wasmtime) and
then reusing the engine in multiple TSLanguages results in a use after
free. With this change, failing to call `wasm_engine_delete` on your
owned Engine results in a memory leak. Memory leaks are safer than
use-after-free.
This commit is contained in:
Ryan Patterson 2024-08-22 21:01:37 +06:00 committed by GitHub
parent 5364ac4ea8
commit b5e4ef6d9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 20 additions and 21 deletions

View file

@ -592,9 +592,9 @@ fn run() -> Result<()> {
if parse_options.wasm {
let engine = tree_sitter::wasmtime::Engine::default();
parser
.set_wasm_store(tree_sitter::WasmStore::new(engine.clone()).unwrap())
.set_wasm_store(tree_sitter::WasmStore::new(&engine).unwrap())
.unwrap();
loader.use_wasm(engine);
loader.use_wasm(&engine);
}
let timeout = parse_options.timeout.unwrap_or_default();
@ -690,9 +690,9 @@ fn run() -> Result<()> {
if test_options.wasm {
let engine = tree_sitter::wasmtime::Engine::default();
parser
.set_wasm_store(tree_sitter::WasmStore::new(engine.clone()).unwrap())
.set_wasm_store(tree_sitter::WasmStore::new(&engine).unwrap())
.unwrap();
loader.use_wasm(engine);
loader.use_wasm(&engine);
}
let languages = loader.languages_at_path(&current_dir)?;

View file

@ -33,7 +33,7 @@ fn test_wasm_stdlib_symbols() {
#[test]
fn test_load_wasm_ruby_language() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm = fs::read(WASM_DIR.join("tree-sitter-ruby.wasm")).unwrap();
let language = store.load_language("ruby", &wasm).unwrap();
@ -50,7 +50,7 @@ fn test_load_wasm_ruby_language() {
#[test]
fn test_load_wasm_html_language() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm = fs::read(WASM_DIR.join("tree-sitter-html.wasm")).unwrap();
let language = store.load_language("html", &wasm).unwrap();
@ -69,7 +69,7 @@ fn test_load_wasm_html_language() {
#[test]
fn test_load_wasm_rust_language() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm = fs::read(WASM_DIR.join("tree-sitter-rust.wasm")).unwrap();
let language = store.load_language("rust", &wasm).unwrap();
@ -83,7 +83,7 @@ fn test_load_wasm_rust_language() {
#[test]
fn test_load_wasm_javascript_language() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm = fs::read(WASM_DIR.join("tree-sitter-javascript.wasm")).unwrap();
let language = store.load_language("javascript", &wasm).unwrap();
@ -97,7 +97,7 @@ fn test_load_wasm_javascript_language() {
#[test]
fn test_load_multiple_wasm_languages() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm_cpp = fs::read(WASM_DIR.join("tree-sitter-cpp.wasm")).unwrap();
@ -113,7 +113,7 @@ fn test_load_multiple_wasm_languages() {
let mut parser2 = Parser::new();
parser2
.set_wasm_store(WasmStore::new(ENGINE.clone()).unwrap())
.set_wasm_store(WasmStore::new(&ENGINE).unwrap())
.unwrap();
let mut query_cursor = QueryCursor::new();
@ -174,7 +174,7 @@ fn test_load_multiple_wasm_languages() {
#[test]
fn test_load_and_reload_wasm_language() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let wasm_rust = fs::read(WASM_DIR.join("tree-sitter-rust.wasm")).unwrap();
let wasm_typescript = fs::read(WASM_DIR.join("tree-sitter-typescript.wasm")).unwrap();
@ -199,18 +199,18 @@ fn test_load_and_reload_wasm_language() {
#[test]
fn test_reset_wasm_store() {
allocations::record(|| {
let mut language_store = WasmStore::new(ENGINE.clone()).unwrap();
let mut language_store = WasmStore::new(&ENGINE).unwrap();
let wasm = fs::read(WASM_DIR.join("tree-sitter-rust.wasm")).unwrap();
let language = language_store.load_language("rust", &wasm).unwrap();
let mut parser = Parser::new();
let parser_store = WasmStore::new(ENGINE.clone()).unwrap();
let parser_store = WasmStore::new(&ENGINE).unwrap();
parser.set_wasm_store(parser_store).unwrap();
parser.set_language(&language).unwrap();
let tree = parser.parse("fn main() {}", None).unwrap();
assert_eq!(tree.root_node().to_sexp(), "(source_file (function_item name: (identifier) parameters: (parameters) body: (block)))");
let parser_store = WasmStore::new(ENGINE.clone()).unwrap();
let parser_store = WasmStore::new(&ENGINE).unwrap();
parser.set_wasm_store(parser_store).unwrap();
let tree = parser.parse("fn main() {}", None).unwrap();
assert_eq!(tree.root_node().to_sexp(), "(source_file (function_item name: (identifier) parameters: (parameters) body: (block)))");
@ -220,7 +220,7 @@ fn test_reset_wasm_store() {
#[test]
fn test_load_wasm_errors() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let wasm = fs::read(WASM_DIR.join("tree-sitter-rust.wasm")).unwrap();
let bad_wasm = &wasm[1..];
@ -252,7 +252,7 @@ fn test_load_wasm_errors() {
#[test]
fn test_wasm_oom() {
allocations::record(|| {
let mut store = WasmStore::new(ENGINE.clone()).unwrap();
let mut store = WasmStore::new(&ENGINE).unwrap();
let mut parser = Parser::new();
let wasm = fs::read(WASM_DIR.join("tree-sitter-html.wasm")).unwrap();
let language = store.load_language("html", &wasm).unwrap();