Skip to content

Memory leak when calling guest functions with env-vars #389

Description

@wujunzhuo
  1. This is a very simple Rust guest function, which just prints out an environment variable USER:

    #[no_mangle]
    pub extern "C" fn hello() {
        println!("hello: {:?}", std::env::var("USER").ok());
    }
  2. If we execute this function repeatedly, then we will see the program can load env-vars correctly; but the program memory usage keeps increasing. (I've also tested other wasm implementations as well, e.g. WasmEdge crate)

    use anyhow::Result;
    use wasmtime::{Engine, Linker, Module, Store};
    use wasmtime_wasi::WasiCtxBuilder;
    
    const WASM_FILE: &str = "/tmp/hello.wasm";
    
    fn main() -> Result<()> {
        let engine = Engine::default();
        let mut linker = Linker::new(&engine);
        wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
        let wasi = WasiCtxBuilder::new().inherit_env()?.inherit_stdio().build();
        let mut store = Store::new(&engine, wasi);
        let module = Module::from_file(&engine, WASM_FILE)?;
        let instance = linker.instantiate(&mut store, &module)?;
        let func = instance.get_typed_func::<(), ()>(&mut store, "hello")?;
        loop {
            func.call(&mut store, ())?;
        }
    }
    wujunzhuo@wujunzhuo-macbook demo % ./target/debug/hello
    hello: Some("wujunzhuo")
    hello: Some("wujunzhuo")
    hello: Some("wujunzhuo")
    hello: Some("wujunzhuo")
    # monitor memory
    wujunzhuo@wujunzhuo-macbook Desktop % do
        sleep 1
        ps -p $(pidof hello) -o %mem,rss
    done
    
    %MEM    RSS
    0.4  65536
    %MEM    RSS
    0.5  80032
    %MEM    RSS
    0.6  94496
    %MEM    RSS
    0.6 108928
    %MEM    RSS
    0.7 123376
    %MEM    RSS
    0.8 137824
    %MEM    RSS
    0.9 152288
    %MEM    RSS
    1.0 166688
    %MEM    RSS
    1.1 181168
  3. I found the __wasilibc_initialize_environ function might be the root cause of the memory leak, and after changing some lines like the following, the program could run normally.

    wujunzhuo@wujunzhuo-macbook wasi-libc % git diff
    diff --git a/libc-bottom-half/sources/__wasilibc_initialize_environ.c b/libc-bottom-half/sources/__wasilibc_initialize_environ.c
    index 2d31c5d..65738d1 100644
    --- a/libc-bottom-half/sources/__wasilibc_initialize_environ.c
    +++ b/libc-bottom-half/sources/__wasilibc_initialize_environ.c
    @@ -15,7 +15,7 @@ weak char **__wasilibc_environ = (char **)-1;
    
    // See the comments in libc-environ.h.
    void __wasilibc_ensure_environ(void) {
    -    if (__wasilibc_environ == (char **)-1) {
    +    if (__wasilibc_environ == (char **)-1 || __wasilibc_environ == NULL) {
            __wasilibc_initialize_environ();
        }
    }
    diff --git a/libc-bottom-half/sources/environ.c b/libc-bottom-half/sources/environ.c
    index 50d60de..fedfc83 100644
    --- a/libc-bottom-half/sources/environ.c
    +++ b/libc-bottom-half/sources/environ.c
    @@ -20,12 +20,12 @@ weak_alias(__wasilibc_environ, environ);
    // reserved things to go before or after.
    __attribute__((constructor(50)))
    static void __wasilibc_initialize_environ_eagerly(void) {
    -    __wasilibc_initialize_environ();
    +    __wasilibc_ensure_environ();
    }
    
    // See the comments in libc-environ.h.
    void __wasilibc_maybe_reinitialize_environ_eagerly(void) {
        // This translation unit is linked in if `environ` is used, meaning we need
        // to eagerly reinitialize the environment variables.
    -    __wasilibc_initialize_environ();
    +    __wasilibc_ensure_environ();
    }
    %MEM    RSS
    0.2  25680
    %MEM    RSS
    0.2  28336
    %MEM    RSS
    0.2  28336
    %MEM    RSS
    0.2  28336
    %MEM    RSS
    0.2  28336
    %MEM    RSS
    0.2  28336
    %MEM    RSS
    0.2  28336
    %MEM    RSS
    0.2  28336

    However, I can't figure out why __wasilibc_environ might be initialized to NULL: since if we only compare it with -1, the wasm function couldn't load any environment variable:

    wujunzhuo@wujunzhuo-macbook demo % ./target/debug/hello
    hello: None
    hello: None
    hello: None

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions