Search code examples
lua

How to get and set lightuserdata


I want to store a pointer into the lua_State object, and retrieve that pointer in callbacks. It's just the same, single pointer, in all callbacks. I think what I need is lightuserdata, but I can't find complete examples on how to set and fetch the pointer.

I just need something this simple:

void SetPointer(lua_State* L, void* p) {
    lua_pushlightuserdata (l, p);
    // What else to do?
}

void GetPointer(lua_State* L) {
    // How to get the lightuserdata?
}

I can do it either using the raw Lua API or using the Sol wrapper library [1]

[1] https://github.com/ThePhD/sol2


Solution

  • Make sure that you really don't want to use full userdata (in most cases you want). Read e.g., PIL 28.5 - Light Userdata to get a better idea.

    To use light userdata you need to manage its lifetime in C side and availability in Lua all on your own. To set and get light userdata on/from Lua stack use respectively: lua_pushlightuserdata and lua_touserdata (this function is shared with full userdata). You can also use lua_topointer to read the pointer value; note that it has wider and slightly different use.

    To allocate and make it available:

    char* obj = malloc(2);  // lifetime managed by C
    obj[0] = 'U';
    obj[1] = 0;
    lua_pushlightuserdata(L, obj);
    lua_setglobal(L, "ptr");  // make it available to Lua via global variable
    

    Afterwards, you can use it in Lua:

    print(ptr)  --> userdata: 0x556be32ba2e0
    another = ptr
    

    And in C:

    lua_getglobal(L, "another");  // another global from the previous sample
    void* ref1 = lua_touserdata(L, -1);
    printf("%p\n", ref1);  //: 0x556be32ba2e0
    const void* ref2 = lua_topointer(L, -1);
    printf("%p\n", ref2);  //: 0x556be32ba2e0
    lua_pop(L, 1);
    

    Finally, you will need to free the allocated object at the correct spot:

    free(obj);  // again, lifetime managed by C
    

    Now, where is "the correct spot"? Well... It's where you would usually put it when writing in pure C: when you (or your user) no longer need it or never (e.g., if you like memory leaks, your program is short-lived or object lifetime is same as program lifetime).

    As an alternative to global variable, you may put the pointer into the Registry. This will make it accessible to you via the Lua state in C but not from the Lua side:

    char* obj;  // initialize it as before
    lua_pushstring(L, "myprogram_that_one_object");  // prefix your key, registry is shared with all libraries
    lua_pushlightuserdata(L, obj);
    lua_settable(L, LUA_REGISTRYINDEX);
    

    Then, in possibly another scope, when you want to use or free it:

    lua_pushstring(L, "myprogram_that_one_object");
    lua_gettable(L, LUA_REGISTRYINDEX);
    char* obj = lua_touserdata(L, -1);
    free(obj);  // or use it
    lua_pop(L, 1);
    

    If you use full userdata, Lua will manage the lifetime of the object for you (it will be garbage collected just like normal Lua values).