Stream: wasmtime

Topic: memory leak in wasi-nn


view this post on Zulip Masahiro Kozuka (Sep 09 2025 at 01:05):

Hello.

I found a memory leak in wasi-nn. When we call compute(), a tensor which is passed from wasm will be leaked because wasm pass its owenership but host doesn't comsume it.

I find this leak will be fixed with the following change.
https://github.com/seera-networks/wasmtime/commit/d1ac513d00b0cd3e2a869544c2bc067b5f6298b3

How can I contribute this change?

A lightweight WebAssembly runtime that is fast, secure, and standards-compliant - fix memory leak · seera-networks/wasmtime@d1ac513

view this post on Zulip fitzgen (he/him) (Sep 09 2025 at 17:12):

a pull request is the preferred way to propose code changes

cc @Andrew Brown for wasi-nn stuff

view this post on Zulip Christof Petig (Sep 09 2025 at 22:31):

I memorized that within the Component model the host never frees data allocated by the guest directly, this is the purpose of the matching post_cabi function. Can you check whether this is the case here as well?

view this post on Zulip Andrew Brown (Sep 09 2025 at 22:36):

Yes, I believe you will want the guest to drop the tensor once you're done with it in whatever language you are using wasi-nn (what language are you using?). The appropriate self.table.delete(...) invocation happens in HostTensor::drop: https://github.com/bytecodealliance/wasmtime/blob/9d64c5250fa6d1eb1541c4e2d26da0ca6608ae21/crates/wasi-nn/src/wit.rs#L321-L324.

A lightweight WebAssembly runtime that is fast, secure, and standards-compliant - bytecodealliance/wasmtime

view this post on Zulip Masahiro Kozuka (Sep 11 2025 at 00:56):

Thank you for your reply! I'm using Rust. I think that it is the best to invoke self.table.delete() in HostTensor::drop(), but I have no idea to invoke HostTensor::drop() from guest.

The following is my guest code:

    let tensor = Tensor::new(&tensor_dim, TensorType::Fp32, &input_tensor);
    let named_tensor = vec![("images".to_string(), tensor)];
    let outputs = ctx.compute(named_tensor).unwrap();

In this code, the owenership of tensor will be passed, so HostTensor::drop will never be invoked. This is the reason why I suppose that we should invoke self.table.delete() in compute().

view this post on Zulip Masahiro Kozuka (Sep 14 2025 at 00:37):

@Andrew Brown What do you think about my understanding? Do I misunderstand something?

view this post on Zulip Andrew Brown (Sep 14 2025 at 03:55):

I had thought that passing a resource in a WIT signature meant borrowing but your example makes me rethink that: Rust certainly expects ownership to transfer there. I guess I'm uncertain now: @Pat Hickey, does passing a resource as an argument transfer ownership or borrow the resource?

view this post on Zulip Christof Petig (Sep 14 2025 at 11:10):

If the argument is wrapped in borrow<> it isn't consumed, as is the self argument in methods. But transfer clearly is the default.

view this post on Zulip Andrew Brown (Sep 15 2025 at 21:09):

Ok, this makes sense. I was unaware of the own/borrow notation when I switched wasi-nn from WITX to WIT long ago, so @Masahiro Kozuka's change makes complete sense if we are passing ownership of the tensor. @Masahiro Kozuka, do you want to submit a PR with this change?

view this post on Zulip Andrew Brown (Sep 15 2025 at 21:09):

In the future, we could debate changing the specification to borrow instead (probably the original intention), but for now this change would fix the bug.

view this post on Zulip Masahiro Kozuka (Sep 16 2025 at 08:01):

Thanks. I will submit a PR in a few days.

view this post on Zulip Masahiro Kozuka (Sep 17 2025 at 07:06):

@Andrew Brown I sent a PR.

This PR will fix a memory leak in wasi-nn, which does'nt free the tensor resource whose owenership is transferred. You can find a discussion in the zulip.

Last updated: Dec 06 2025 at 06:05 UTC