Skip to content

Luau: userdata referencing itself through set_user_value is not collected #720

Description

@pcbzzz

Reproduction

Tested against 8eddf85.

[dependencies]
mlua = {
    git = "https://github.com/mlua-rs/mlua",
    rev = "8eddf85de0e1576f07145d04201d07ca108d963c",
    features = ["luau"]
}
use std::cell::Cell;
use std::rc::Rc;

use mlua::{Lua, Result, UserData};

struct Tracked(Rc<Cell<usize>>);

impl UserData for Tracked {}

impl Drop for Tracked {
    fn drop(&mut self) {
        self.0.set(self.0.get() + 1);
    }
}

fn collected_after_gc(lua: &Lua, self_user_value: bool) -> Result<usize> {
    let drops = Rc::new(Cell::new(0));

    {
        let userdata = lua.create_userdata(Tracked(Rc::clone(&drops)))?;

        if self_user_value {
            userdata.set_user_value(userdata.clone())?;
        } else {
            userdata.set_user_value(42)?;
        }
    }

    lua.gc_collect()?;
    lua.gc_collect()?;

    Ok(drops.get())
}

fn main() -> Result<()> {
    let lua = Lua::new();

    assert_eq!(collected_after_gc(&lua, false)?, 1);
    assert_eq!(collected_after_gc(&lua, true)?, 1);

    Ok(())
}

The second assertion fails with a drop count of 0. Additional calls to gc_collect do not collect it.

The same test passes with the Lua 5.4 backend.

Expected behavior

The userdata should be collectible once the external handle is dropped. set_user_value accepts any Lua value and does not document a restriction on values that reference the userdata.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions