DMD GC causing segfault
Closed this issue · 9 comments
Code here http://paste.pocoo.org/show/270340/
Back trace here http://paste.pocoo.org/show/270342/
I haven't been able to reproduce this bug.
Starting from the bottom of the provided snippet, could you try removing one line at a time until the bug goes away? I think that would help pinpointing where the erronous LuaObject is created.
I have the same issue. I'm on 64-bit Ubuntu and I had to change a few "int"s to "long"s to get it to compile. All that is necessary to cause the segfault is to create a LuaState. Here's my backtrace with some more symbols:
#0 0x000000000040877c in lua_rawgeti (L=0x6bbaa0, idx=-10000, n=0) at lapi.c:573
#1 0x000000000041be10 in luaL_unref (L=0x6bbaa0, t=-10000, ref=2) at lauxlib.c:507
#2 0x00000000004058ed in luad.reference.LuaReference.__dtor() ()
#3 0x0000000000405792 in luad.base.LuaObject.__fieldDtor() ()
#4 0x0000000000452102 in rt_finalize (p=0x7ffff7edaf20, det=false) at ../../../libphobos/rt/lifetime.d:1133
#5 0x000000000045e25a in fullcollect (this=..., stackTop=) at ../../../libphobos/gc/gcx.d:2568
#6 0x000000000045e4a9 in fullcollectshell (this=...) at ../../../libphobos/gc/gcx.d:2329
#7 0x000000000045efa1 in fullCollectNoStack (this=...) at ../../../libphobos/gc/gcx.d:1300
#8 0x000000000045bfb4 in gc_term () at ../../../libphobos/gc/gc.d:133
#9 0x00000000004518ad in tryExec (dg=...) at ../../../libphobos/rt/dmain2.d:482
#10 0x0000000000451a82 in _d_run_main (argc=2, argv=0x7fffffffe338, main_func=) at ../../../libphobos/rt/dmain2.d:562
#11 0x00007ffff73d3d8e in __libc_start_main () from /lib/libc.so.6
#12 0x0000000000404e39 in _start ()
As you can see, it happens when destructing LuaReference. Here is the offending code in lapi.c:
568 LUA_API void lua_rawgeti (lua_State *L, int idx, int n) {
569 StkId o;
570 lua_lock(L);
571 o = index2adr(L, idx);
572 api_check(L, ttistable(o));
573 setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
574 api_incr_top(L);
575 lua_unlock(L);
576 }
Here are the values of the vars:
L = (lua_State *) 0x6bbaa0
*L = {next = 0x6bc8a0, tt = 152 '\230', marked = 62 '>',
status = 115 's', top = 0x0, base = 0x0, l_G = 0x6bbb58,
ci = 0x6bbd10, savedpc = 0x0, stack_last = 0x6bc0d0,
stack = 0x6bbe60, end_ci = 0x6bbe28, base_ci = 0x6bbd10,
stacksize = 45, size_ci = 8, nCcalls = 0, baseCcalls = 0,
hookmask = 0 '\000', allowhook = 1 '\001', basehookcount = 0,
hookcount = 0, hook = 0, l_gt = {value = {gc = 0x6bb700,
p = 0x6bb700, n = 3.4877082071225276e-317, b = 7059200},
tt = 5}, env = {value = {gc = 0x0, p = 0x0, n = 0, b = 0},
tt = 0}, openupval = 0x0, gclist = 0x0, errorJmp = 0x0,
errfunc = 0}
L->top = (StkId) 0x0
o = (StkId) 0x6bbbf8
n = 0
idx = -10000
It seems a bit odd to me... not sure why it's crashing.
A little more investigation reveals that setobj2s is a macro. Here it is again, expanded:
571 o = index2adr(L, idx);
572 api_check(L, ttistable(o));
573
574 const TValue *o2=(luaH_getnum(hvalue(o), n));
575 TValue *o1=(L->top);
576 o1->value = o2->value;
577 o1->tt=o2->tt;
578 checkliveness(G(L),o1);
576 is the offending line. If you take a look at my previous post, you'll see L->top is 0x0, so o1 is a null pointer that is being accessed.
I believe I've found the problem. When the LuaState object is GC'd, lua_close() is called in the destructor and then afterwards the LuaReference destructor is called, which calls luaL_unref() with a now invalid lua_state.
I'm not sure what the best way to go about fixing it is, so I'll leave that to you :-).
Sorry for replying late,
I'm aware of the problem (also mentioned in other issues like "Calling a delegate containing a LuaFunction throws an exception"), and I decided long ago to refactor the LuaObject and LuaState objects into structs (which also makes use of LuaObject a bit more performant), but I've never gotten around to doing it.
There is a temporary solution which can help in some applications, but the problem and solution should really be mentioned in the docs (since I'm so slow in fixing it):
auto L = luaL_newstate();
auto state = new LuaState(L);
// use state
// When you're sure it's safe to close it:
lua_close(L);
(Requires that you import the C API)
The workaround has some side effects. The LuaD panic handler throwing an exception is not installed by default. See the source code of the two constructors for LuaState on how to solve this.
No problem.
Your workaround still doesn't work because of _G and _R created in the LuaState ctor. If I manually delete these in the LuaState dtor, it fixes the crash, though. I guess _G and _R are the objects that we're getting destructed after the lua_state was closed.
I'm not sure if this fixes the underlying problem (I would guess not), as I'm not that familiar with Lua, or D for that matter, but at least for me, it seems to stop the crashing.
Right, nice find!
Indeed, I don't think it really fixes the underlying problem. The delete operator itself is deprecated, and it still leaves the problem of other LuaObject references hanging around after the LuaState is gone.
Confirmed on a 64-bit platform, also confirmed the workaround in issue #11 (adding that you need to import luad.c.all in order to make luaL_newstate() work, of course).
LuaObject hierarchy are now structs, this bug should be fixed