mlua-rs / mlua

High level Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Roblox Luau bindings to Rust with async/await support
Other
1.76k stars 139 forks source link

Segfault in lua_getallocf in MemoryState::get #479

Closed jedrzejboczar closed 2 weeks ago

jedrzejboczar commented 3 weeks ago

Hi, I am trying to track down a segfault that happens when I'm using lua-json5 plugin from Neovim. I previously described the bug here https://github.com/Joakker/lua-json5/issues/5, but I am now thinking that maybe this is something with mlua itself.

Here is my latest stack traceback with debug symbols enabled:

(gdb) bt
#0  0x0000733f6f76314d in lua_getallocf (L=0x733f69ec1290, ud=0x7ffe219b48b0) at /usr/src/debug/luajit/LuaJIT-97813fb924edf822455f91a5fbbdfdb349e5984f/src/lj_api.c:1309
#1  0x0000733f694fe9a9 in mlua::memory::MemoryState::get () at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/memory.rs:30
#2  mlua::lua::Lua::unlikely_memory_error (self=<optimized out>) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:3223
#3  mlua::lua::Lua::create_table_from<alloc::string::String, lua_json5::val::Value, std::collections::hash::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState>> (self=0x5cd6dd61c3a0, iter=...)
    at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:1435
#4  0x0000733f69503296 in mlua::conversion::{impl#50}::into_lua<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState> (self=..., lua=0x7ffe219b48b0) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/conversion.rs:966
#5  lua_json5::val::{impl#0}::into_lua (self=..., lua=0x7ffe219b48b0) at src/val.rs:21
#6  0x0000733f695075ac in lua_json5::parser::parse (lua=0x5cd6dd61c3a0, data=...) at src/parser.rs:82
#7  0x0000733f694fe541 in core::ops::function::Fn::call<fn(&mlua::lua::Lua, alloc::string::String) -> core::result::Result<mlua::value::Value, mlua::error::Error>, (&mlua::lua::Lua, alloc::string::String)> ()
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/ops/function.rs:79
#8  mlua::lua::{impl#6}::create_function::{closure#0}<alloc::string::String, mlua::value::Value, fn(&mlua::lua::Lua, alloc::string::String) -> core::result::Result<mlua::value::Value, mlua::error::Error>> (lua=0x5cd6dd61c3a0, nargs=<optimized out>)
    at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:1534
#9  0x0000733f6950f51f in mlua::lua::{impl#6}::create_callback::call_callback::{closure#0} (nargs=1) at src/lua.rs:2917
#10 mlua::lua::callback_error_ext::{closure#0}<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32> () at src/lua.rs:3435
#11 core::panic::unwind_safe::{impl#23}::call_once<core::result::Result<i32, mlua::error::Error>, mlua::lua::callback_error_ext::{closure_env#0}<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32>> (self=...)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panic/unwind_safe.rs:272
#12 std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<mlua::lua::callback_error_ext::{closure_env#0}<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32>>, core::result::Result<i32, mlua::error::Error>> (data=<optimized out>)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:559
#13 std::panicking::try<core::result::Result<i32, mlua::error::Error>, core::panic::unwind_safe::AssertUnwindSafe<mlua::lua::callback_error_ext::{closure_env#0}<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32>>> (f=...)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:523
#14 std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<mlua::lua::callback_error_ext::{closure_env#0}<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32>>, core::result::Result<i32, mlua::error::Error>> (f=...)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panic.rs:149
#15 mlua::lua::callback_error_ext<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32> (state=0x733f6f876380, extra=0x5cd6dd61c2f0, f=...) at src/lua.rs:3435
#16 mlua::lua::{impl#6}::create_callback::call_callback (state=0x733f6f876380) at src/lua.rs:2907
#17 0x0000733f6f74ef06 in lj_BC_FUNCC () at buildvm_x86.dasc:857
#18 0x0000733f6f7630aa in lua_pcall (L=L@entry=0x733f6f876380, nargs=nargs@entry=0, nresults=nresults@entry=1, errfunc=errfunc@entry=-2) at /usr/src/debug/luajit/LuaJIT-97813fb924edf822455f91a5fbbdfdb349e5984f/src/lj_api.c:1122
#19 0x00005cd6a758296e in nlua_pcall (nresults=1, lstate=0x733f6f876380, nargs=0) at /usr/src/debug/neovim-git/neovim/src/nvim/lua/executor.c:174
#20 nlua_call_ref.constprop.0 (ref=<optimized out>, name=name@entry=0x0, args=..., err=err@entry=0x7ffe219b5320, arena=<optimized out>, mode=<optimized out>) at /usr/src/debug/neovim-git/neovim/src/nvim/lua/executor.c:1608
#21 0x00005cd6a72e73df in map_execute_lua (may_repeat=true) at /usr/src/debug/neovim-git/neovim/src/nvim/getchar.c:3183
#22 0x00005cd6a73bda7b in nv_colon (cap=0x7ffe219b5520) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:3174
#23 0x00005cd6a73ba1a6 in normal_execute (state=0x7ffe219b54b0, key=<optimized out>) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:1235
#24 0x00005cd6a74b4a1b in state_enter (s=0x7ffe219b54b0) at /usr/src/debug/neovim-git/neovim/src/nvim/state.c:102
#25 0x00005cd6a73b6dca in normal_enter (cmdwin=<optimized out>, noexmode=<optimized out>) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:521
#26 0x00005cd6a7147187 in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/neovim-git/neovim/src/nvim/main.c:660
And with variable values ``` (gdb) bt -full -frame-arguments all -entry-values if-needed #0 0x0000733f6f76314d in lua_getallocf (L=0x733f69ec1290, ud=0x7ffe219b48b0) at /usr/src/debug/luajit/LuaJIT-97813fb924edf822455f91a5fbbdfdb349e5984f/src/lj_api.c:1309 g = 0x33 #1 0x0000733f694fe9a9 in mlua::memory::MemoryState::get () at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/memory.rs:30 mem_state = 0x0 state = 0x733f69ec1290 #2 mlua::lua::Lua::unlikely_memory_error (self=) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:3223 mem_state = mem_state = #3 mlua::lua::Lua::create_table_from> (self=0x5cd6dd61c3a0, iter=std::collections::hash::map::HashMap {base: hashbrown::map::HashMap {hash_builder: std::hash::random::RandomState {k0: 5121892263594791715, k1: 3142564978189085165}, table: hashbrown::raw::RawTable<(alloc::string::String, lua_json5::val::Value), alloc::alloc::Global> {table: hashbrown::raw::RawTableInner {bucket_mask: 3, ctrl: core::ptr::non_null::NonNull {pointer: 0x5cd6dd1d7790}, growth_left: 2, items: 1}, alloc: alloc::alloc::Global, marker: core::marker::PhantomData<(alloc::string::String, lua_json5::val::Value)>}}}) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:1435 lower_bound = 1 iter = std::collections::hash::map::IntoIter { base: hashbrown::map::IntoIter { inner: hashbrown::raw::RawIntoIter<(alloc::string::String, lua_json5::val::Value), alloc::alloc::Global> { iter: hashbrown::raw::RawIter<(alloc::string::String, lua_json5::val::Value)> { iter: hashbrown::raw::RawIterRange<(alloc::string::String, lua_json5::val::Value)> { current_group: hashbrown::raw::bitmask::BitMaskIter ( hashbrown::raw::bitmask::BitMask ( 4 ) ), data: hashbrown::raw::Bucket<(alloc::string::String, lua_json5::val::Value)> { ptr: core::ptr::non_null::NonNull<(alloc::string::String, lua_json5::val::Value)> { pointer: 0x5cd6dd1d7790 } }, next_ctrl: 0x5cd6dd1d77a0, end: 0x5cd6dd1d7794 }, items: 1 }, allocation: core::option::Option<(core::ptr::non_null::NonNull, core::alloc::layout::Layout, alloc::alloc::Global)>::Some(( core::ptr::non_null::NonNull { pointer: 0x5cd6dd1d7650 }, core::alloc::layout::Layout { size: 340, align: core::ptr::alignment::Alignment ( core::ptr::alignment::AlignmentEnum::_Align1Shl4 ) }, alloc::alloc::Global )), marker: core::marker::PhantomData<(alloc::string::String, lua_json5::val::Value)> } } } _sg = mlua::util::StackGuard { state: 0x733f6f876380, top: 1 } state = 0x733f6f876380 #4 0x0000733f69503296 in mlua::conversion::{impl#50}::into_lua ( self=std::collections::hash::map::HashMap {base: hashbrown::map::HashMap {hash_builder: std::hash::random::RandomState {k0: 5121892263594791715, k1: 3142564978189085165}, table: hashbrown::raw::RawTable<(alloc::string::String, lua_json5::val::Value), alloc::alloc::Global> {table: hashbrown::raw::RawTableInner {bucket_mask: 3, ctrl: core::ptr::non_null::NonNull {pointer: 0x5cd6dd1d7790}, growth_left: 2, items: 1}, alloc: alloc::alloc::Global, marker: core::marker::PhantomData<(alloc::string::String, lua_json5::val::Value)>}}}, lua=0x7ffe219b48b0) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/conversion.rs:966 residual = val = #5 lua_json5::val::{impl#0}::into_lua (self=, lua=0x7ffe219b48b0) at src/val.rs:21 o = std::collections::hash::map::HashMap { base: hashbrown::map::HashMap { hash_builder: std::hash::random::RandomState { k0: 5121892263594791715, k1: 3142564978189085165 }, table: hashbrown::raw::RawTable<(alloc::string::String, lua_json5::val::Value), alloc::alloc::Global> { table: hashbrown::raw::RawTableInner { bucket_mask: 3, ctrl: core::ptr::non_null::NonNull { pointer: 0x5cd6dd1d7790 }, growth_left: 2, items: 1 }, alloc: alloc::alloc::Global, marker: core::marker::PhantomData<(alloc::string::String, lua_json5::val::Value)> } } } #6 0x0000733f695075ac in lua_json5::parser::parse (lua=0x5cd6dd61c3a0, data=alloc::string::String {vec: alloc::vec::Vec {buf: alloc::raw_vec::RawVec {ptr: core::ptr::unique::Unique {pointer: core::ptr::non_null::NonNull {pointer: 0x5cd6dd1f7cb0}, _marker: core::marker::PhantomData}, cap: alloc::raw_vec::Cap (3257), alloc: alloc::alloc::Global}, len: 3257}}) at src/parser.rs:82 data = pest::iterators::pair::Pair { queue: alloc::rc::Rc, alloc::alloc::Global>, alloc::alloc::Global> { ptr: core::ptr::non_null::NonNull, alloc::alloc::Global>>> { pointer: 0x5cd6dd8569f0 }, phantom: core::marker::PhantomData, alloc::alloc::Global>>>, alloc: alloc::alloc::Global }, input: "{\n \"configurations\": [\n\n {\n", ' ' , "\"name\": \"Launch & Debug\",\n", ' ' , "\"type\": \"cortex-debug\",\n", ' ' , "\"request\": \"launch\",\n", ' ' , "\"cwd\": \"${workspaceFolder}/build\",\n "..., start: 0, line_index: alloc::rc::Rc { ptr: core::ptr::non_null::NonNull> { pointer: 0x5cd6dd709480 }, phantom: core::marker::PhantomData>, alloc: alloc::alloc::Global } } #7 0x0000733f694fe541 in core::ops::function::Fn::call core::result::Result, (&mlua::lua::Lua, alloc::string::String)> () at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/ops/function.rs:79 No locals. #8 mlua::lua::{impl#6}::create_function::{closure#0} core::result::Result> (lua=0x5cd6dd61c3a0, nargs=) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:1534 args = alloc::string::String { vec: alloc::vec::Vec { buf: alloc::raw_vec::RawVec { ptr: core::ptr::unique::Unique { pointer: core::ptr::non_null::NonNull { pointer: 0x33 }, _marker: core::marker::PhantomData }, cap: alloc::raw_vec::Cap ( 102077902452628 ), alloc: alloc::alloc::Global }, len: } } func = #9 0x0000733f6950f51f in mlua::lua::{impl#6}::create_callback::call_callback::{closure#0} (nargs=1) at src/lua.rs:2917 func = *const dyn core::ops::function::Fn<(&mlua::lua::Lua, i32), Output=core::result::Result> { pointer: 0x7ffe219b48b0, vtable: 0x33 } _guard = mlua::lua::StateGuard ( 0x5cd6dd76d3d0, 0x733f69ec1290 ) lua = 0x5cd6dd61c3a0 upvalue = extra = state = lua = _guard = func = #10 mlua::lua::callback_error_ext::{closure#0} () at src/lua.rs:3435 f = nargs = #11 core::panic::unwind_safe::{impl#23}::call_once, mlua::lua::callback_error_ext::{closure_env#0}> (self=) at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panic/unwind_safe.rs:272 _args = #12 std::panicking::try::do_call>, core::result::Result> (data=) at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:559 data = data = f = #13 std::panicking::try, core::panic::unwind_safe::AssertUnwindSafe>> (f=) at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:523 data = data = data_ptr = #14 std::panic::catch_unwind>, core::result::Result> (f=) at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panic.rs:149 No locals. #15 mlua::lua::callback_error_ext (state=0x733f6f876380, extra=0x5cd6dd61c2f0, f=) at src/lua.rs:3435 prealloc_failure = mlua::lua::callback_error_ext::PreallocatedFailure::Existing(2) nargs = 1 nargs = prealloc_failure = r = p = wrapped_panic = err = wrapped_error = traceback = cause = traceback = #16 mlua::lua::{impl#6}::create_callback::call_callback (state=0x733f6f876380) at src/lua.rs:2907 upvalue = 0x733f6990cf28 extra = #17 0x0000733f6f74ef06 in lj_BC_FUNCC () at buildvm_x86.dasc:857 No locals. #18 0x0000733f6f7630aa in lua_pcall (L=0x733f6f876380, nargs=0, nresults=1, errfunc=-2) at /usr/src/debug/luajit/LuaJIT-97813fb924edf822455f91a5fbbdfdb349e5984f/src/lj_api.c:1122 g = 0x733f6f8763e0 oldh = 0 '\000' ef = status = #19 0x00005cd6a758296e in nlua_pcall (nresults=1, lstate=0x733f6f876380, nargs=0) at /usr/src/debug/neovim-git/neovim/src/nvim/lua/executor.c:174 status = status = #20 nlua_call_ref.constprop.0 (ref=, name=0x0, args={size = 0, capacity = , items = }, err=0x7ffe219b5320, arena=, mode=) at /usr/src/debug/neovim-git/neovim/src/nvim/lua/executor.c:1608 lstate = 0x733f6f876380 nargs = 0 #21 0x00005cd6a72e73df in map_execute_lua (may_repeat=true) at /usr/src/debug/neovim-git/neovim/src/nvim/getchar.c:3183 line_ga = { ga_len = , ga_maxlen = , ga_itemsize = , ga_growsize = , ga_data = 0x5cd6dd5b3170 } c1 = 13 aborted = false ref = err = { type = kErrorTypeNone, msg = 0x0 } args = { size = 0, capacity = 0, items = 0x0 } #22 0x00005cd6a73bda7b in nv_colon (cap=0x7ffe219b5520) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:3174 cmd_result = is_cmdkey = false is_lua = true #23 0x00005cd6a73ba1a6 in normal_execute (state=0x7ffe219b54b0, key=) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:1235 s = 0x7ffe219b54b0 #24 0x00005cd6a74b4a1b in state_enter (s=0x7ffe219b54b0) at /usr/src/debug/neovim-git/neovim/src/nvim/state.c:102 check_result = key = execute_result = getkey = #25 0x00005cd6a73b6dca in normal_enter (cmdwin=, noexmode=) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:521 state = { state = { check = 0x5cd6a73b8c30 , execute = 0x5cd6a73b9640 }, command_finished = false, ctrl_w = false, need_flushbuf = false, set_prevcount = false, previous_got_int = false, cmdwin = false, noexmode = false, toplevel = true, oa = { op_type = 0, regname = 0, motion_type = kMTCharWise, motion_force = 0, use_reg_one = false, inclusive = false, end_adjusted = false, start = { lnum = 0, col = 0, coladd = 0 }, end = { lnum = 0, col = 0, coladd = 0 }, cursor_start = { lnum = 0, col = 0, coladd = 0 }, line_count = 0, empty = false, is_VIsual = false, start_vcol = 0, end_vcol = 0, prev_opcount = 0, prev_count0 = 0, excl_tr_ws = false }, ca = { oap = 0x7ffe219b54c8, prechar = 0, cmdchar = -26621, nchar = 0, ncharC1 = 0, ncharC2 = 0, extra_char = 0, opcount = 0, count0 = 0, count1 = 1, arg = 0, retval = 0, searchbuf = 0x0 }, mapped_len = 0, old_mapped_len = 0, idx = 187, c = -26621, old_col = 0, old_pos = { lnum = 1, col = 0, coladd = 0 } } prev_oap = 0x0 #26 0x00005cd6a7147187 in main (argc=, argv=) at /usr/src/debug/neovim-git/neovim/src/nvim/main.c:660 fname = params = { argc = 3, argv = 0x7ffe219b5af8, use_vimrc = 0x0, clean = false, n_commands = 0, commands = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, cmds_tofree = "\000\000\000\000\000\000\000\000\000", n_pre_commands = 0, pre_commands = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, luaf = 0x0, lua_arg0 = -1, edit_type = 0, tagname = 0x0, use_ef = 0x0, input_istext = false, no_swap_file = 0, use_debug_break_level = -1, window_count = 1, window_layout = 3, diff_mode = 0, listen_addr = 0x0, remote = 0, server_addr = 0x0, scriptin = 0x0, scriptout = 0x0, scriptout_append = false, had_stdin_file = false } cwd = 0x0 has_term = use_builtin_ui = remote_ui = use_remote_ui = listen_and_embed = vimrc_none = ```

It looks like it fails on if (ud) *ud = g->allocd; here:

(gdb) list
1304    }
1305
1306    LUA_API lua_Alloc lua_getallocf(lua_State *L, void **ud)
1307    {
1308      global_State *g = G(L);
1309      if (ud) *ud = g->allocd;
1310      return g->allocf;
1311    }
1312
1313    LUA_API void lua_setallocf(lua_State *L, lua_Alloc f, void *ud)
(gdb) disassemble
Dump of assembler code for function lua_getallocf:
   0x0000733f6f763140 <+0>:     endbr64
   0x0000733f6f763144 <+4>:     mov    0x10(%rdi),%rax
   0x0000733f6f763148 <+8>:     test   %rsi,%rsi
   0x0000733f6f76314b <+11>:    je     0x733f6f763154 <lua_getallocf+20>
=> 0x0000733f6f76314d <+13>:    mov    0x8(%rax),%rdx
   0x0000733f6f763151 <+17>:    mov    %rdx,(%rsi)
   0x0000733f6f763154 <+20>:    mov    (%rax),%rax
   0x0000733f6f763157 <+23>:    ret
End of assembler dump.

The exact address is a little different than in https://github.com/Joakker/lua-json5/issues/5#issuecomment-2426277452, but it looks is an offset into global_State which itself has address near 0:

(gdb) p $_siginfo._sifields._sigfault
$1 = {
  si_addr = 0x3b,
  _addr_lsb = 0,
  _addr_bnd = {
    _lower = 0x0,
    _upper = 0x0
  }
}
(gdb) p g
$4 = (global_State *) 0x33
(gdb) p/x (int) & ((global_State *) 0)->allocd
$5 = 0x8
(gdb) p/x 0x33 + (int) & ((global_State *) 0)->allocd
$6 = 0x3b

I'm also adding the contnet of self inside mlua::lua::Lua::create_table_from:

(gdb) down
#3  mlua::lua::Lua::create_table_from<alloc::string::String, lua_json5::val::Value, std::collections::hash::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState>> (self=0x5cd6dd61c3a0, iter=...)
    at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:1435
1435                let protect = !self.unlikely_memory_error();
(gdb) p *self
$16 = mlua::lua::Lua (
  alloc::sync::Arc<mlua::lua::LuaInner, alloc::alloc::Global> {
    ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<mlua::lua::LuaInner>> {
      pointer: 0x5cd6dd76d3c0
    },
    phantom: core::marker::PhantomData<alloc::sync::ArcInner<mlua::lua::LuaInner>>,
    alloc: alloc::alloc::Global
  }
)
(gdb) p *self.__0.ptr.pointer
$17 = alloc::sync::ArcInner<mlua::lua::LuaInner> {
  strong: core::sync::atomic::AtomicUsize {
    v: core::cell::UnsafeCell<usize> {
      value: 1
    }
  },
  weak: core::sync::atomic::AtomicUsize {
    v: core::cell::UnsafeCell<usize> {
      value: 1
    }
  },
  data: mlua::lua::LuaInner {
    state: core::sync::atomic::AtomicPtr<mlua_sys::lua51::lua::lua_State> {
      p: core::cell::UnsafeCell<*mut mlua_sys::lua51::lua::lua_State> {
        value: 0x733f6f876380
      }
    },
    main_state: 0x733f69ec1290,
    extra: alloc::sync::Arc<core::cell::UnsafeCell<mlua::lua::ExtraData>, alloc::alloc::Global> {
      ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<core::cell::UnsafeCell<mlua::lua::ExtraData>>> {
        pointer: 0x5cd6dd61c2e0
      },
      phantom: core::marker::PhantomData<alloc::sync::ArcInner<core::cell::UnsafeCell<mlua::lua::ExtraData>>>,
      alloc: alloc::alloc::Global
    }
  }
}

Do you have any idea what might be the problem? Or is it not related to mlua but something else up the stack?

khvzak commented 3 weeks ago

Is it possible that you loaded lua-json5 module from non-main coroutine (lua state)? E.g. somewhere inside a function rather than on top level during neovim loading.

jedrzejboczar commented 3 weeks ago

I am not sure but this might be the case. lua-json5 is being lazy-loaded when executing a neovim key mapping callback.

The exact execution is:

The lazy loading is done by https://github.com/folke/lazy.nvim plugin manager, and I don't think it does the loading in a coroutine. When I put print(debug.traceback('loading lua-json5')) inside lazy.nvim's config handler for lua-json5 I can see the following:

loading lua-json5
stack traceback:
    ~/.config/nvim/lua/jb/plugins/dap/init.lua:321: in function 'config'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:376: in function <...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:374>
    [C]: in function 'xpcall'
    .../.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/util.lua:135: in function 'try'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:391: in function 'config'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:358: in function '_load'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:197: in function 'load'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:352: in function <...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:351>
    [C]: in function 'xpcall'
    .../.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/util.lua:135: in function 'try'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:351: in function '_load'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:197: in function 'load'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:539: in function 'auto_load'
    ...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:560: in function <...local/share/nvim/lazy/lazy.nvim/lua/lazy/core/loader.lua:548>
    [C]: in function 'require'
    ~/.config/nvim/lua/jb/plugins/telescope/pickers.lua:898: in function 'get_dap_configurations'
    ~/.config/nvim/lua/jb/plugins/telescope/pickers.lua:936: in function <~/.config/nvim/lua/jb/plugins/telescope/pickers.lua:933>

So it looks like the call is not rooted in init.lua but I'd assume it's still running on the main coroutine?

Note that I don't get segfault in most cases, for some reason it only happens sometimes, so it might be that the call stack is different when the segfault happens.

Anyway, I'll try to disable lazy-loading of lua-json5 and see if it helps.

khvzak commented 3 weeks ago

On first load, mlua tries to obtain a main state (main coroutine) from Lua. Lua 5.1/JIT don't have a method for that (Lua 5.2+ has) so instead current coroutine saved and reused.

It's possible that after lazy loading from non-main coroutine, it was destroyed and then reused to obtain allocation handler. Otherwise I don't see any other reasons why g->allocd; refers to invalid address. I can change this behaviour to always use current (active) Lua thread instead.

it calls my Lua handler (I suppose this is called from main coroutine?)

I'm not sure about this. From the backtrace we can see that coroutine used to call MemoryState::get (0x733f6f876380) is different from the coroutine where module was loaded (0x733f69ec1290) and marked as main.

jedrzejboczar commented 3 weeks ago

Ok, thanks for the analysis. I will report back if the segfault happens again now, when I removed lazy-loading of lua-json5. Had no problems yet, but I'd wait a few days.

khvzak commented 2 weeks ago

Please reopen if the problem still exists. I pushed a fix already