Skip to content

Wrong garbage collection local variable #510

Open
@rise0chen

Description

@rise0chen
use core::time::Duration;
use futures_util::future::select_all;
use mlua::prelude::*;

async fn sleep(_lua: Lua, ms: u64) -> LuaResult<()> {
    tokio::time::sleep(Duration::from_millis(ms)).await;
    Ok(())
}
async fn select(_lua: Lua, threads: LuaMultiValue) -> LuaResult<(LuaValue, i64)> {
    let futs: Vec<LuaAsyncThread<_, LuaValue>> = threads
        .into_iter()
        .filter_map(|thread| {
            if let LuaValue::Thread(thread) = thread {
                Some(thread.into_async(()))
            } else {
                None
            }
        })
        .collect();
    if futs.is_empty() {
        return Ok((LuaValue::Nil, -1));
    }
    let (val, index, _threads) = select_all(futs).await;
    Ok((val?, index as i64 + 1))
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> LuaResult<()> {
    let lua = Lua::new();
    lua.globals().set("sleep", lua.create_async_function(sleep)?)?;
    lua.globals()
        .set("select_all", lua.create_async_function(select)?)?;
    lua.set_hook(LuaHookTriggers::EVERY_LINE, move |_lua, debug| {
        let source = debug.source().source.unwrap_or(std::borrow::Cow::Borrowed("~"));
        let is_rust = source.len() < 2;
        // println!("lua hook({}): {}", is_rust, source);
        if is_rust {
            Ok(LuaVmState::Continue)
        } else {
            Ok(LuaVmState::Yield)
        }
    });

    let f = lua
        .load(
            r#"
            function f_test()
                while true
                do
                    local d = {0,0,0,0,0,0}
                    d[1] = d[1] + 1
                    d[2] = d[2] + 2
                    d[3] = d[3] + 3
                    d[4] = d[4] + 4
                    d[5] = d[5] + 5
                    d[6] = d[6] + 6
            
                    sleep(5)
                end
            end

            function f_gc()
                while true
                do
                    sleep(50)
                    collectgarbage("collect")
                end
            end

            ret, index = select_all(coroutine.create(f_test), coroutine.create(f_gc))
            print(ret, index)
        "#,
        )
        .into_function()?;
    let thread = lua.create_thread(f)?;
    thread.into_async(()).await?;

    Ok(())
}
cargo run --release --features=lua54,vendored,async --example b 
   Compiling mlua v0.10.2
    Finished `release` profile [optimized] target(s) in 8.11s
     Running `target/release/examples/b`
Error: CallbackError { traceback: "stack traceback:\n\t[C]: in local 'poll'\n\t[string \"?\"]:4: in function 'select_all'\n\t[string \"examples/b.rs:45:10\"]:25: in main chunk", cause: RuntimeError("[string \"examples/b.rs:45:10\"]:6: attempt to index a nil value (local 'd')\nstack traceback:\n\t[string \"examples/b.rs:45:10\"]:6: in function 'f_test'") }

It throw an error: attempt to index a nil value (local 'd')

I think this issue is related to set_hook.

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