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: crash on tab switch with multiwindow enabled #522

Open
Frestein opened this issue Nov 11, 2024 · 4 comments · Fixed by #525 · May be fixed by #526
Open

bug: crash on tab switch with multiwindow enabled #522

Frestein opened this issue Nov 11, 2024 · 4 comments · Fixed by #525 · May be fixed by #526
Labels
bug Something isn't working

Comments

@Frestein
Copy link

Frestein commented Nov 11, 2024

Description

@apollo1321 I am experiencing a crash with the nvim-treesitter-context feature when using Neovim with the multiwindow option enabled.

I was unable to reproduce the bug with the minimal configuration. Additionally, Neovim does not output any messages upon crashing that could help identify the cause of the crash.

Neovim version

NVIM v0.10.2 Build type: RelWithDebInfo LuaJIT 2.1.1727870382

Expected behavior

I expect to be able to close the current tab and return to the previous tab without any issues, and the context of the file should be displayed correctly.

Actual behavior

Upon returning to the previous tab after closing a new tab, Neovim crashes to the shell without redrawing the UI and does not generate any error logs.

echo $?
139

Image

Minimal config

vim.g.mapleader = " "

local plugins = {
ts = "https://github.com/nvim-treesitter/nvim-treesitter",
ts_context = "https://github.com/nvim-treesitter/nvim-treesitter-context",
snacks = "https://github.com/folke/snacks.nvim",
}

for name, url in pairs(plugins) do
local install_path = "/tmp/nvim/site/" .. name
if vim.fn.isdirectory(install_path) == 0 then
vim.fn.system({ "git", "clone", "--depth=1", url, install_path })
end
vim.o.runtimepath = install_path .. "," .. vim.o.runtimepath
end

require("snacks").setup({})
vim.keymap.set("n", "<leader>gg", function()
require("snacks").lazygit()
end)
require("nvim-treesitter.configs").setup({ ensure_installed = { "lua" } })
require("treesitter-context").setup({ multiwindow = true })

Steps to reproduce

My configuration:
https://github.com/Frestein/NvChan

  1. Open any file in a new tab using lazygit, where the context should be displayed.
  2. Close the tab (using zz or :tabclose).
  3. Return to the previous tab where another file's context should be displayed.
@Frestein Frestein added the bug Something isn't working label Nov 11, 2024
@apollo1321
Copy link
Contributor

I have reproduced this segfault and here is the stacktrace:

#0  0x0000558d2ab0290c in winframe_find_altwin ()
#1  0x0000558d2ab05b71 in winframe_remove ()
#2  0x0000558d2ab092d0 in win_close_othertab ()
#3  0x0000558d2ab23c02 in close_last_window_tabpage.part.0.lto_priv ()
#4  0x0000558d2ab097e7 in win_close ()
#5  0x0000558d2a8a8a8d in execute_cmd0 ()
#6  0x0000558d2a8ac284 in do_cmdline ()
#7  0x0000558d2a9b2835 in nv_colon.lto_priv ()
#8  0x0000558d2a9ab57c in normal_execute.lto_priv ()
#9  0x0000558d2aa8d3f4 in state_enter ()
#10 0x0000558d2a9aa9fc in normal_enter ()
#11 0x0000558d2a777601 in main ()

@apollo1321
Copy link
Contributor

apollo1321 commented Nov 11, 2024

And here is more detailed stacktrace from neovim debug build, 7919aa9102e1b9b7a9f7feaea6b134a98f5b60fc. This issue looks similar:
neovim/neovim#29112

0x00005ed61ba065fc in frame2win (frp=0x0) at /home/apollo1321/neovim/src/nvim/window.c:3474
3474      while (frp->fr_win == NULL) {
(gdb) bt
#0  0x00005ed61ba065fc in frame2win (frp=0x0) at /home/apollo1321/neovim/src/nvim/window.c:3474
#1  0x00005ed61ba05cab in winframe_find_altwin (win=0x5ed61cc1f2a0, dirp=0x7ffd9ced9578, tp=0x5ed61c5214b0, altfr=0x7ffd9ced94c8) at /home/apollo1321/neovim/src/nvim/window.c:3211
#2  0x00005ed61ba05a6e in winframe_remove (win=0x5ed61cc1f2a0, dirp=0x7ffd9ced9578, tp=0x5ed61c5214b0, unflat_altfr=0x0) at /home/apollo1321/neovim/src/nvim/window.c:3148
#3  0x00005ed61ba059c5 in win_free_mem (win=0x5ed61cc1f2a0, dirp=0x7ffd9ced9578, tp=0x5ed61c5214b0) at /home/apollo1321/neovim/src/nvim/window.c:3072
#4  0x00005ed61ba05924 in win_close_othertab (win=0x5ed61cc1f2a0, free_buf=0, tp=0x5ed61c5214b0) at /home/apollo1321/neovim/src/nvim/window.c:3050
#5  0x00005ed61ba04a64 in close_last_window_tabpage (win=0x5ed61cc1f2a0, free_buf=false, prev_curtab=0x5ed61c5214b0) at /home/apollo1321/neovim/src/nvim/window.c:2609
#6  0x00005ed61ba04e13 in win_close (win=0x5ed61cc1f2a0, free_buf=false, force=false) at /home/apollo1321/neovim/src/nvim/window.c:2711
#7  0x00005ed61b7a8d66 in ex_quit (eap=0x7ffd9ced97b0) at /home/apollo1321/neovim/src/nvim/ex_docmd.c:4776
#8  0x00005ed61b7a0cd3 in execute_cmd0 (retv=0x7ffd9ced9768, eap=0x7ffd9ced97b0, errormsg=0x7ffd9ced9780, preview=false) at /home/apollo1321/neovim/src/nvim/ex_docmd.c:1714
#9  0x00005ed61b7a2b8c in do_one_cmd (cmdlinep=0x7ffd9ced99d0, flags=0, cstack=0x7ffd9ced9ae0, fgetline=0x5ed61b7bbb44 <getexline>, cookie=0x0) at /home/apollo1321/neovim/src/nvim/ex_docmd.c:2358
#10 0x00005ed61b79e66e in do_cmdline (cmdline=0x0, fgetline=0x5ed61b7bbb44 <getexline>, cookie=0x0, flags=0) at /home/apollo1321/neovim/src/nvim/ex_docmd.c:667
#11 0x00005ed61b8a5385 in nv_colon (cap=0x7ffd9ceda150) at /home/apollo1321/neovim/src/nvim/normal.c:3190
#12 0x00005ed61b8a0e1c in normal_execute (state=0x7ffd9ceda0e0, key=58) at /home/apollo1321/neovim/src/nvim/normal.c:1243
#13 0x00005ed61b980bb6 in state_enter (s=0x7ffd9ceda0e0) at /home/apollo1321/neovim/src/nvim/state.c:102
#14 0x00005ed61b89ef7b in normal_enter (cmdwin=false, noexmode=false) at /home/apollo1321/neovim/src/nvim/normal.c:521
#15 0x00005ed61b842872 in main (argc=3, argv=0x7ffd9ceda4e8) at /home/apollo1321/neovim/src/nvim/main.c:660

@apollo1321
Copy link
Contributor

apollo1321 commented Nov 14, 2024

Minimal reproducing config:

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)

require("lazy").setup({
  spec = {
    {
      "nvim-treesitter/nvim-treesitter-context",
      opts = {
        enable = true,
        multiwindow = true,
      },
    },
  },
})

It appears that the lazy plugin calls setup() twice: initially with multi-window support disabled, and then with it enabled. This was unexpected and likely leads to confusing event sequences, potentially causing Neovim to crash.

@apollo1321
Copy link
Contributor

It seems my PR fixes this problem unreliably. There's a chance that the creation of a window won't be deferred, allowing the same issue to occur.
The satellite.nvim plugin addresses this by always executing deferred callbacks: https://github.com/lewis6991/satellite.nvim/blob/main/lua/satellite.lua#L41
I plan to adopt this approach for a more reliable fix, as a Neovim fix might take a long time and won't be applied to older versions.

@apollo1321 apollo1321 linked a pull request Nov 17, 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
2 participants