lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

On Wed, Sep 13, 2017 at 4:02 PM, ThePhD <> wrote:
> Observe the following complete, compile-able (and mostly C) code, which
> stores a simple "luaL_ref" wrapper in a struct named "co_test" and links up
> a simple creation method ("new") and a simple deletion method ("__gc"):
> void co_test_destroy(co_test* p) {
>     luaL_unref(p->L, LUA_REGISTRYINDEX, p->ref);
>     p->ref = 0;
>     p->L = NULL;
> }
> int co_test___gc(lua_State* L) {
>     co_test* p = (co_test*)lua_touserdata(L, 1);
>     co_test_destroy(p);
>     return 0;
> }
> In "co_test_destroy", the code segfaults (g++, clang++) / "Read Access
> Violation" (VC++) when doing "luaL_unref" when this code executes. I found
> that the reason is that the "co" variable, which holds the coroutine and
> thread represented by the "L" that the "co_test" was created with, dies. If
> you do not explicitly "nil" the "co" variable in the Lua code, the
> thread/state that "co_test" is created with stays alive.
> This behavior is observable in Lua 5.3, 5.2 and 5.1 (but not with LuaJIT on
> VC++ and Windows, for some reason).
> I am unsure of how to get around this issue properly. I know in 5.2 and 5.3
> I can forcefully obtain the main thread's state and thusly avoid this
> problem altogether by just adjusting the "L" pointer in the "co_test_new"
> function. But I seem to be on an island for Lua 5.1.

Have you tried passing the lua_state from _gc to _destroy and using
that state to unref?

I mean:

void co_test_destroy(lua_State * L, co_test* p) { *** Extra parameter.
    luaL_unref(L, LUA_REGISTRYINDEX, p->ref); *** Using parameter
instead of the data stored in p.
     p->ref = 0;
     p->L = NULL;
int co_test___gc(lua_State* L) {
     co_test* p = (co_test*)lua_touserdata(L, 1);
     co_test_destroy(L, p); *** Passing calling state, which must be ok.
    return 0;

> Does anyone have any thoughts about this? Is this behavior desirable? Should
> I just ask my users to collect garbage before setting any coroutine/thread
> wrappers to "nil"?

Well, you are using a dead state, behaviour may be undesirable, but I
would call it expected.

Francisco Olarte