Stream: git-wasmtime

Topic: wasmtime / Issue #2583 Memory never dropped if captured i...


view this post on Zulip Wasmtime GitHub notifications bot (Jan 14 2021 at 10:47):

bkolobara labeled Issue #2583:

Hi, I'm using wasmtime = 0.21 and run into a bug where the Memory is never dropped if moved inside a closure passed to Linker::func.

Here is a minimal example:

use wasmtime::*;

struct MyMemory {}
unsafe impl LinearMemory for MyMemory {
    fn size(&self) -> u32 {
        0
    }

    fn grow(&self, _delta: u32) -> Option<u32> {
        None
    }

    fn as_ptr(&self) -> *mut u8 {
        std::ptr::null_mut()
    }
}

impl Drop for MyMemory {
    fn drop(&mut self) {
        println!("Dropped!")
    }
}

struct MyMemoryCreator {}
unsafe impl MemoryCreator for MyMemoryCreator {
    fn new_memory(
        &self,
        _ty: MemoryType,
        _reserved_size_in_bytes: Option<u64>,
        _guard_size_in_bytes: u64,
    ) -> Result<Box<dyn LinearMemory>, String> {
        Ok(Box::new(MyMemory {}))
    }
}

fn main() {
    let mut config = Config::new();
    config.with_host_memory(std::sync::Arc::new(MyMemoryCreator {}));
    let engine = Engine::new(&config);
    let store = Store::new(&engine);
    let mut linker = Linker::new(&store);
    let memory_ty = MemoryType::new(Limits::new(1, None));
    let memory = Memory::new(&store, memory_ty);
    let captured_memory = memory.clone();
    linker
        .func("", "", move || {
            let _ = captured_memory;
        })
        .unwrap();
}

MyMemory and MyMemoryCreator are added here only for the purpose of printing out on drop, but the same behaviour is observed with the default Memory.

In this example "Dropped!" is never printed out, but if I comment out let _ = captured_memory; it is. I assume there is somewhere a cycle in reference counting.

I'm also aware that the instance memory can be accessed through the first argument (Caller), but because of some other design decisions I prefer capturing some memories this way. Would this be considered a bug or a Memory should never be captured like this?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 14 2021 at 10:47):

bkolobara opened Issue #2583:

Hi, I'm using wasmtime = 0.21 and run into a bug where the Memory is never dropped if moved inside a closure passed to Linker::func.

Here is a minimal example:

use wasmtime::*;

struct MyMemory {}
unsafe impl LinearMemory for MyMemory {
    fn size(&self) -> u32 {
        0
    }

    fn grow(&self, _delta: u32) -> Option<u32> {
        None
    }

    fn as_ptr(&self) -> *mut u8 {
        std::ptr::null_mut()
    }
}

impl Drop for MyMemory {
    fn drop(&mut self) {
        println!("Dropped!")
    }
}

struct MyMemoryCreator {}
unsafe impl MemoryCreator for MyMemoryCreator {
    fn new_memory(
        &self,
        _ty: MemoryType,
        _reserved_size_in_bytes: Option<u64>,
        _guard_size_in_bytes: u64,
    ) -> Result<Box<dyn LinearMemory>, String> {
        Ok(Box::new(MyMemory {}))
    }
}

fn main() {
    let mut config = Config::new();
    config.with_host_memory(std::sync::Arc::new(MyMemoryCreator {}));
    let engine = Engine::new(&config);
    let store = Store::new(&engine);
    let mut linker = Linker::new(&store);
    let memory_ty = MemoryType::new(Limits::new(1, None));
    let memory = Memory::new(&store, memory_ty);
    let captured_memory = memory.clone();
    linker
        .func("", "", move || {
            let _ = captured_memory;
        })
        .unwrap();
}

MyMemory and MyMemoryCreator are added here only for the purpose of printing out on drop, but the same behaviour is observed with the default Memory.

In this example "Dropped!" is never printed out, but if I comment out let _ = captured_memory; it is. I assume there is somewhere a cycle in reference counting.

I'm also aware that the instance memory can be accessed through the first argument (Caller), but because of some other design decisions I prefer capturing some memories this way. Would this be considered a bug or a Memory should never be captured like this?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 14 2021 at 15:50):

alexcrichton commented on Issue #2583:

This is unfortunately expected behavior right now, albeit one we may want to investigate fixing with additional APIs. The problem is that you're creating a cycle of Rc (Store owns Func data which owns Memory which owns the same Store) which never gets freed. This is a known drawback of Rc in Rust, but currently a design decision in Wasmtime.

Ideally if you can the best fix would be to use the Caller structure which handles this correctly. Otherwise we may need to provide "weak" forms of things like Memory so you can close over the weak verisons without inducing a reference cycle.


Last updated: Dec 23 2024 at 12:05 UTC