Skip to content

Fix wasip1 memory leak#12599

Open
mbund wants to merge 2 commits intobytecodealliance:mainfrom
mbund:wasip1-resource-table-memory-leak-fix
Open

Fix wasip1 memory leak#12599
mbund wants to merge 2 commits intobytecodealliance:mainfrom
mbund:wasip1-resource-table-memory-leak-fix

Conversation

@mbund
Copy link

@mbund mbund commented Feb 16, 2026

I use wasmtime to host a long lived wasip1 program, and I discovered a memory leak.

The issue is in async wasip1 contexts. The minimal code to reproduce (is taken from the existing wasip1-async example):

// cargo build --example wasip1-async --release
use wasmtime::Result;
use wasmtime::{Engine, Linker, Module, Store};
use wasmtime_wasi::WasiCtx;
use wasmtime_wasi::p1::{self, WasiP1Ctx};

#[tokio::main]
async fn main() -> Result<()> {
    let engine = Engine::default();

    let mut linker: Linker<WasiP1Ctx> = Linker::new(&engine);
    p1::add_to_linker_async(&mut linker, |t| t)?;

    let wasi_ctx = WasiCtx::builder().inherit_stdio().build_p1();

    let mut store = Store::new(&engine, wasi_ctx);

    let module = Module::from_file(&engine, "target/wasm32-wasip1/release/wasi.wasm")?;
    let func = linker
        .module_async(&mut store, "", &module)
        .await?
        .get_default(&mut store, "")?
        .typed::<(), ()>(&store)?;

    func.call_async(&mut store, ()).await?;

    Ok(())
}

As well as a minimal wasm program:

// cargo build -p example-wasi-wasm --target wasm32-wasip1 --release
fn main() {
    loop {
        std::thread::sleep(std::time::Duration::from_millis(1));
    }
}

Now, running the program in heaptrack with heaptrack ./target/release/examples/wasip1-async, we can see that there is a problem:

image

It grows by megabytes in minutes.

The issue was in wasmtime_wasi::p2::host::clocks::subscribe_to_duration (and an underlying Vec grow). If I understand correctly, wasip1 is implemented in terms of wasip2. Wasip2 creates pollables and hands them off to a guest app, but the wasip1 code was just creating pollables and never dropping them. So to fix it, I just drop those pollables after we are done using them. Also, I added code to drop the partial pollable list if it encounters an error while still creating more pollables.

And here is a screenshot of heaptrack on my fix branch, after :

image

Perfectly flat, even after a long time!

I was not able to find an open issue about this, so I just made this PR. Let me know if this fix is sensible or what I can do to make it more robust.

@mbund mbund requested a review from a team as a code owner February 16, 2026 09:02
@github-actions github-actions bot added the wasi Issues pertaining to WASI label Feb 16, 2026
@alexcrichton alexcrichton self-requested a review February 16, 2026 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasi Issues pertaining to WASI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant