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

bug: time_t is the wrong size on i686-musl #1820

Open
4 tasks done
remexre opened this issue Nov 20, 2024 · 2 comments · May be fixed by #1821
Open
4 tasks done

bug: time_t is the wrong size on i686-musl #1820

remexre opened this issue Nov 20, 2024 · 2 comments · May be fixed by #1821
Labels
bug Something isn't working

Comments

@remexre
Copy link

remexre commented Nov 20, 2024

Did you check docs and existing issues?

  • I have read all the lazy.nvim docs
  • I have updated the plugin to the latest version before submitting this issue
  • I have searched the existing issues of lazy.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

v0.11.0-dev-1201+g0e2f92ed79

Operating system/version

Alpine Linux v3.14

Describe the bug

(Note: this reproduces on a wide variety of Neovim commits, and on later versions of Alpine and on Gentoo with a musl profile.)

lazy.nvim segfaults on i686-musl systems. It seems that this can be fixed with the following patch:

diff --git a/lua/lazy/stats.lua b/lua/lazy/stats.lua
index 015a2be..5195a56 100644
--- a/lua/lazy/stats.lua
+++ b/lua/lazy/stats.lua
@@ -34,51 +34,51 @@ end
 function M.cputime()
   if M.C == nil then
     pcall(function()
       ffi.cdef([[
         typedef long time_t;
         typedef int clockid_t;
         typedef struct timespec {
           time_t   tv_sec;        /* seconds */
           long     tv_nsec;       /* nanoseconds */
         } nanotime;
         int clock_gettime(clockid_t clk_id, struct timespec *tp);
       ]])
       M.C = ffi.C
     end)
   end

   local function real()
     local pnano = assert(ffi.new("nanotime[?]", 1))
     local CLOCK_PROCESS_CPUTIME_ID = jit.os == "OSX" and 12 or 2
     ffi.C.clock_gettime(CLOCK_PROCESS_CPUTIME_ID, pnano)
     return tonumber(pnano[0].tv_sec) * 1e3 + tonumber(pnano[0].tv_nsec) / 1e6
   end

   local function fallback()
     return (vim.uv.hrtime() - require("lazy")._start) / 1e6
   end

-  local ok, ret = pcall(real)
-  if ok then
-    M.cputime = real
-    M._stats.real_cputime = true
-    return ret
-  else
+  -- local ok, ret = pcall(real)
+  -- if ok then
+    -- M.cputime = real
+    -- M._stats.real_cputime = true
+    -- return ret
+  -- else
     M.cputime = fallback
     return fallback()
-  end
+  -- end
 end

 function M.stats()
   M._stats.count = 0
   M._stats.loaded = 0
   for _, plugin in pairs(require("lazy.core.config").plugins) do
     M._stats.count = M._stats.count + 1
     if plugin._.loaded then
       M._stats.loaded = M._stats.loaded + 1
     end
   end
   return M._stats
 end

 return M

The typedef long time_t; is certainly incorrect here -- long is int32_t on i686, but time_t is int64_t.

(This is insufficient to fix the segfault, but it's at least an easy thing to fix.)

FWIW, an example stack trace on segfault is:

#0  0x56a8e8fe in lj_alloc_free (msp=0xf7e98008, ptr=<optimized out>) at lj_alloc.c:1400
#1  0x56abb727 in lj_mem_free (osize=<optimized out>, p=0xf7de6940, g=0xf7e981f8)
    at /code/.deps/build/src/luajit/src/lj_gc.h:122
#2  lj_cdata_free (g=0xf7e981f8, cd=<optimized out>) at lj_cdata.c:83
#3  0x56a97077 in gc_sweep (g=g@entry=0xf7e981f8, p=0xf7e92218, lim=9, lim@entry=40) at lj_gc.c:423
#4  0x56a97d6a in gc_onestep (L=0xf7e981c8) at lj_gc.c:683
#5  0x56a9840b in lj_gc_step (L=L@entry=0xf7e981c8) at lj_gc.c:732
#6  0x56a851d7 in lj_parse_keepstr (ls=ls@entry=0xffef0ca8, str=0xf7e9f2b1 "` changed `dir`:\n- from: `\"", len=26)
    at lj_parse.c:246
#7  0x56a820bd in lex_string (tv=<optimized out>, ls=0xffef0ca8) at lj_lex.c:285
#8  lex_scan (ls=ls@entry=0xffef0ca8, tv=tv@entry=0xffef0cb0) at lj_lex.c:368
#9  0x56a82a05 in lj_lex_next (ls=ls@entry=0xffef0ca8) at lj_lex.c:460
#10 0x56a85806 in expr_binop (ls=ls@entry=0xffef0ca8, v=v@entry=0xffef02a8, limit=limit@entry=4) at lj_parse.c:2118
#11 0x56a85d7f in expr_binop (ls=ls@entry=0xffef0ca8, v=v@entry=0xffef0360, limit=limit@entry=0) at lj_parse.c:2121
#12 0x56a88678 in expr (v=0xffef0360, ls=0xffef0ca8) at lj_parse.c:2132
#13 expr_list (v=0xffef0360, ls=0xffef0ca8) at lj_parse.c:1899
#14 parse_local (ls=0xffef0ca8) at lj_parse.c:2284
#15 parse_stmt (ls=0xffef0ca8) at lj_parse.c:2676
#16 parse_chunk (ls=ls@entry=0xffef0ca8) at lj_parse.c:2713
#17 0x56a87b57 in parse_block (ls=0xffef0ca8) at lj_parse.c:2429
#18 parse_then (ls=0xffef0ca8) at lj_parse.c:2619
#19 parse_if (line=99, ls=0xffef0ca8) at lj_parse.c:2629
#20 parse_stmt (ls=0xffef0ca8) at lj_parse.c:2655
#21 parse_chunk (ls=ls@entry=0xffef0ca8) at lj_parse.c:2713
#22 0x56a87b57 in parse_block (ls=0xffef0ca8) at lj_parse.c:2429
#23 parse_then (ls=0xffef0ca8) at lj_parse.c:2619
#24 parse_if (line=95, ls=0xffef0ca8) at lj_parse.c:2629
#25 parse_stmt (ls=0xffef0ca8) at lj_parse.c:2655
#26 parse_chunk (ls=ls@entry=0xffef0ca8) at lj_parse.c:2713
#27 0x56a853a3 in parse_body (ls=ls@entry=0xffef0ca8, e=e@entry=0xffef08e0, needself=<optimized out>,
    line=line@entry=71) at lj_parse.c:1876
#28 0x56a87713 in parse_func (line=71, ls=0xffef0ca8) at lj_parse.c:2309
#29 parse_stmt (ls=0xffef0ca8) at lj_parse.c:2672
#30 parse_chunk (ls=ls@entry=0xffef0ca8) at lj_parse.c:2713
#31 0x56a88aed in lj_parse (ls=ls@entry=0xffef0ca8) at lj_parse.c:2747
#32 0x56a88be4 in cpparser (L=0xf7e981c8, dummy=0x0, ud=0xffef0ca8) at lj_load.c:50
#33 0x56a9539c in lj_vm_cpcall ()
#34 0x56a88da7 in lua_loadx (L=L@entry=0xf7e981c8, reader=reader@entry=0x56a88c90 <reader_file>,
    data=data@entry=0xffef0d6c,
    chunkname=chunkname@entry=0xf7e28afc "@/root/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/meta.lua",
    mode=mode@entry=0x0) at lj_load.c:72
#35 0x56a88ef2 in luaL_loadfilex (L=L@entry=0xf7e981c8,
    filename=filename@entry=0xf7ddbf3c "/root/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/meta.lua",
    mode=mode@entry=0x0) at lj_load.c:117
#36 0x56ac6877 in lj_cf_loadfile (L=0xf7e981c8) at lib_base.c:386
#37 0x56a95078 in lj_BC_FUNCC ()
#38 0x56acbfc4 in lj_cf_package_require (L=0xf7e981c8) at lib_package.c:453
#39 0x56a95078 in lj_BC_FUNCC ()
#40 0x56acc0b9 in lj_cf_package_require (L=0xf7e981c8) at lib_package.c:464
#41 0x56a95078 in lj_BC_FUNCC ()
#42 0x56acc0b9 in lj_cf_package_require (L=0xf7e981c8) at lib_package.c:464
#43 0x56a95078 in lj_BC_FUNCC ()
#44 0x56a80af4 in lua_pcall (L=0xf7e981c8, nargs=0, nresults=0, errfunc=-2) at lj_api.c:1151
#45 0x5683d2d5 in nlua_pcall (lstate=0xf7e981c8, nargs=0, nresults=0) at ../src/nvim/lua/executor.c:174
#46 0x56841700 in nlua_exec_file (path=0xf7e0a3a0 "/root/.config/nvim/init.lua") at ../src/nvim/lua/executor.c:1860
#47 0x56935789 in do_source (fname=0xf7e11cb0 "/root/.config/nvim/init.lua", check_other=1, is_vimrc=1, ret_sid=0x0)
    at ../src/nvim/runtime.c:2224
#48 0x5684faad in do_user_initialization () at ../src/nvim/main.c:1995
#49 0x5684ffa5 in source_startup_scripts (parmp=0xffef1604) at ../src/nvim/main.c:2108
#50 0x5684c102 in main (argc=2, argv=0xffef1764) at ../src/nvim/main.c:463

How exactly we get to gc_sweep differs, but the trace always ends in those same frames #0-#3.

Steps To Reproduce

  1. Be on an i686-musl platform. (The muslcc/i686:i686-linux-musl Docker container is sufficient.)

  2. Use the following init.lua:

    -- Bootstrap lazy.nvim
    local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
    if not (vim.uv or vim.loop).fs_stat(lazypath) then
      local lazyrepo = "https://github.com/folke/lazy.nvim.git"
      local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
      if vim.v.shell_error ~= 0 then
        vim.api.nvim_echo({
          { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
          { out, "WarningMsg" },
          { "\nPress any key to exit..." },
        }, true, {})
        vim.fn.getchar()
        os.exit(1)
      end
    end
    vim.opt.rtp:prepend(lazypath)
    
    -- Make sure to setup `mapleader` and `maplocalleader` before
    -- loading lazy.nvim so that mappings are correct.
    -- This is also a good place to setup other settings (vim.opt)
    vim.g.mapleader = " "
    vim.g.maplocalleader = "\\"
    
    -- Setup lazy.nvim
    require("lazy").setup({
    })
    
    collectgarbage()
  3. Open nvim ~/.config/nvim/init.lua (or another not-tiny file; if it doesn't repro, open another/larger file)

  4. Get a segfault

Expected Behavior

Don't segfault

Repro

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
  spec = {
    -- add any other plugins here
  },
})

-- not always necessary
collectgarbage()
@remexre remexre added the bug Something isn't working label Nov 20, 2024
@folke
Copy link
Owner

folke commented Nov 20, 2024

So your fix is to just disable the cpu time??

@remexre
Copy link
Author

remexre commented Nov 20, 2024

Not a fix, a "debugging patch" -- it seems that it's pointing at that block as being related to the problem. The time_t definition, I can at least verify as being ABI-incorrect, so it could be the cause of the memory corruption, but I think there's something else there too (since just changing it to long long is insufficient to fix the segfault.)

@remexre remexre linked a pull request Nov 20, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants