Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault in lua_getallocf in MemoryState::get #479

Closed
jedrzejboczar opened this issue Nov 4, 2024 · 5 comments
Closed

Segfault in lua_getallocf in MemoryState::get #479

jedrzejboczar opened this issue Nov 4, 2024 · 5 comments

Comments

@jedrzejboczar
Copy link

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 Joakker/lua-json5#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=<optimized out>) at /home/jb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mlua-0.9.7/src/lua.rs:3223
        mem_state = <optimized out>
        mem_state = <optimized out>
#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=std::collections::hash::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState> {base: hashbrown::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState, alloc::alloc::Global> {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<u8> {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<alloc::string::String, lua_json5::val::Value> {
          base: hashbrown::map::IntoIter<alloc::string::String, lua_json5::val::Value, alloc::alloc::Global> {
            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<u8>, core::alloc::layout::Layout, alloc::alloc::Global)>::Some((
                  core::ptr::non_null::NonNull<u8> {
                    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<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState> (
    self=std::collections::hash::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState> {base: hashbrown::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState, alloc::alloc::Global> {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<u8> {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 = <error reading variable residual (Cannot access memory at address 0x0)>
        val = <optimized out>
#5  lua_json5::val::{impl#0}::into_lua (self=<optimized out>, lua=0x7ffe219b48b0) at src/val.rs:21
        o = std::collections::hash::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState> {
          base: hashbrown::map::HashMap<alloc::string::String, lua_json5::val::Value, std::hash::random::RandomState, alloc::alloc::Global> {
            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<u8> {
                  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<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x5cd6dd1f7cb0}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (3257), alloc: alloc::alloc::Global}, len: 3257}}) at src/parser.rs:82
        data = pest::iterators::pair::Pair<lua_json5::parser::Rule> {
          queue: alloc::rc::Rc<alloc::vec::Vec<pest::iterators::queueable_token::QueueableToken<lua_json5::parser::Rule>, alloc::alloc::Global>, alloc::alloc::Global> {
            ptr: core::ptr::non_null::NonNull<alloc::rc::RcBox<alloc::vec::Vec<pest::iterators::queueable_token::QueueableToken<lua_json5::parser::Rule>, alloc::alloc::Global>>> {
              pointer: 0x5cd6dd8569f0
            },
            phantom: core::marker::PhantomData<alloc::rc::RcBox<alloc::vec::Vec<pest::iterators::queueable_token::QueueableToken<lua_json5::parser::Rule>, alloc::alloc::Global>>>,
            alloc: alloc::alloc::Global
          },
          input: "{\n    \"configurations\": [\n\n        {\n", ' ' <repeats 12 times>, "\"name\": \"Launch & Debug\",\n", ' ' <repeats 12 times>, "\"type\": \"cortex-debug\",\n", ' ' <repeats 12 times>, "\"request\": \"launch\",\n", ' ' <repeats 12 times>, "\"cwd\": \"${workspaceFolder}/build\",\n         "...,
          start: 0,
          line_index: alloc::rc::Rc<pest::iterators::line_index::LineIndex, alloc::alloc::Global> {
            ptr: core::ptr::non_null::NonNull<alloc::rc::RcBox<pest::iterators::line_index::LineIndex>> {
              pointer: 0x5cd6dd709480
            },
            phantom: core::marker::PhantomData<alloc::rc::RcBox<pest::iterators::line_index::LineIndex>>,
            alloc: alloc::alloc::Global
          }
        }
#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
No locals.
#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
        args = alloc::string::String {
          vec: alloc::vec::Vec<u8, alloc::alloc::Global> {
            buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {
              ptr: core::ptr::unique::Unique<u8> {
                pointer: core::ptr::non_null::NonNull<u8> {
                  pointer: 0x33
                },
                _marker: core::marker::PhantomData<u8>
              },
              cap: alloc::raw_vec::Cap (
                102077902452628
              ),
              alloc: alloc::alloc::Global
            },
            len: <optimized out>
          }
        }
        func = <optimized out>
#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<i32, mlua::error::Error>> {
          pointer: 0x7ffe219b48b0,
          vtable: 0x33
        }
        _guard = mlua::lua::StateGuard (
          0x5cd6dd76d3d0,
          0x733f69ec1290
        )
        lua = 0x5cd6dd61c3a0
        upvalue = <optimized out>
        extra = <error reading variable extra (Cannot access memory at address 0x0)>
        state = <optimized out>
        lua = <optimized out>
        _guard = <optimized out>
        func = <optimized out>
#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
        f = <optimized out>
        nargs = <optimized out>
#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=<optimized out>)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panic/unwind_safe.rs:272
        _args = <optimized out>
#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
        data = <optimized out>
        data = <optimized out>
        f = <optimized out>
#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=<optimized out>)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:523
        data = <optimized out>
        data = <optimized out>
        data_ptr = <optimized out>
#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=<optimized out>)
    at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panic.rs:149
No locals.
#15 mlua::lua::callback_error_ext<mlua::lua::{impl#6}::create_callback::call_callback::{closure_env#0}, i32> (state=0x733f6f876380, extra=0x5cd6dd61c2f0, f=<optimized out>) at src/lua.rs:3435
        prealloc_failure = mlua::lua::callback_error_ext::PreallocatedFailure::Existing(2)
        nargs = 1
        nargs = <optimized out>
        prealloc_failure = <error reading variable prealloc_failure (Cannot access memory at address 0x0)>
        r = <optimized out>
        p = <optimized out>
        wrapped_panic = <error reading variable wrapped_panic (Cannot access memory at address 0x0)>
        err = <error reading variable err (Cannot access memory at address 0x0)>
        wrapped_error = <error reading variable wrapped_error (Cannot access memory at address 0x0)>
        traceback = <optimized out>
        cause = <optimized out>
        traceback = <optimized out>
#16 mlua::lua::{impl#6}::create_callback::call_callback (state=0x733f6f876380) at src/lua.rs:2907
        upvalue = 0x733f6990cf28
        extra = <optimized out>
#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 = <optimized out>
        status = <optimized out>
#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 = <optimized out>
        status = <optimized out>
#20 nlua_call_ref.constprop.0 (ref=<optimized out>, name=0x0, args={size = 0, capacity = <optimized out>, items = <optimized out>}, err=0x7ffe219b5320, arena=<optimized out>, mode=<optimized out>) 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 = <optimized out>,
          ga_maxlen = <optimized out>,
          ga_itemsize = <optimized out>,
          ga_growsize = <optimized out>,
          ga_data = 0x5cd6dd5b3170
        }
        c1 = 13
        aborted = false
        ref = <optimized out>
        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 = <optimized out>
        is_cmdkey = false
        is_lua = true
#23 0x00005cd6a73ba1a6 in normal_execute (state=0x7ffe219b54b0, key=<optimized out>) 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 = <optimized out>
        key = <optimized out>
        execute_result = <optimized out>
        getkey = <optimized out>
#25 0x00005cd6a73b6dca in normal_enter (cmdwin=<optimized out>, noexmode=<optimized out>) at /usr/src/debug/neovim-git/neovim/src/nvim/normal.c:521
        state = {
          state = {
            check = 0x5cd6a73b8c30 <normal_check>,
            execute = 0x5cd6a73b9640 <normal_execute>
          },
          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=<optimized out>, argv=<optimized out>) at /usr/src/debug/neovim-git/neovim/src/nvim/main.c:660
        fname = <optimized out>
        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 = <optimized out>
        use_builtin_ui = <optimized out>
        remote_ui = <optimized out>
        use_remote_ui = <optimized out>
        listen_and_embed = <optimized out>
        vimrc_none = <optimized out>

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 Joakker/lua-json5#5 (comment), 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
Copy link
Member

khvzak commented Nov 4, 2024

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
Copy link
Author

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:

  • I enter keys for this keymap
  • it calls my Lua handler (I suppose this is called from main coroutine?)
  • during handler execution lua-json5 is lazy-loaded (as dependency of another package but I guess it's not relevant here)
  • a JSON file is read from filesystem
  • lua-json5 is used to parse it

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
Copy link
Member

khvzak commented Nov 4, 2024

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.

khvzak added a commit that referenced this issue Nov 4, 2024
…only).

When mlua module is loaded from a non-main coroutine we store a reference to it to use later.
If the coroutine is destroyed by GC we can pass a wrong pointer to Lua that will trigger a segfault.
Instead, set main_state as Option and use current (active) state if needed.
Relates to #479
@jedrzejboczar
Copy link
Author

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
Copy link
Member

khvzak commented Nov 9, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants