How to debug intermittent Neovim freezes?

Hello all,

I was considering making a GH issue, but I don’t think I have enough information for it to be useful, so I thought I’d ask here first.

I’ve been happily using neovim as one of my primary editors for years across my Mac and a few Linux (Arch, Raspbian, NixOS) systems; since 0.6 it’s more and more becoming my primary! I am usually running it inside tmux.

However, I’ve had an intermittent freezing issue for years that I’d love to learn how to debug.

Essentially, the neovim window just seems to almost freeze – no keys seem to register. I can still switch tmux panes back and forth to and from neovim and it seems to work (the cursor activates), but nothing else registers – <C-c>, <C-[>, :, Esc, ZZ, :qa!, etc etc – like nothing is being pressed. Happens on both Mac and Linux. From another pane, pkill nvim does nothing; I have to pkill -9 nvim which immediately works.

Today, when I finally decided to dig in a bit, I tried looking under strace and I don’t see any other output other than this one line:

$ sudo strace -p $(pgrep nvim)                                                                                                                                                                   
strace: Process 868731 attached                                                                                        
futex(0x55bc5752276c, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, FUTEX_BITSET_MATCH_ANY

I installed gdb and attached to the process, but frankly I don’t know what to do from there.

When this hang happens again (I wish I knew how to reliably trigger it – it just seems random), what can I do to debug or gather more information on what is going on?

I presume it could be an issue with a plugin, but it only happens once every couple of days, so I imagine selectively disabling plugins could take a long time to determine whether or not the issue is associated with a specific plugin. Is there another approach I could try?

Thanks in advance for any suggestions.

EDIT: Also should note that I don’t see this behavior with any other app I can think of, including vim.

Happened again today, but this time on MacOS. Still no great ideas. Unfortunately I have SIP enabled so no dtrace / dtruss.

are you using terminal inside neovim?
if it is a terminal maybe this can help Neovim crashes if pressing the toggle command in fzf inside toggleterm · Issue #17956 · neovim/neovim · GitHub .

Not when this happens, no.

Things that haven’t worked:

(2 link limit for new users)

I installed gdb and attached to the process, but frankly I don’t know what to do from there.

You should use the bt command, which will print a backtrace. This will give you an idea of where neovim might be stuck. You can use the up and down commands to go from a stack frame to another. You will also be able to use the p command to print variables.

Share the backtrace here once you have it, this will help us decide how to investigate this :slight_smile:

Thanks so much for the step-by-step next time this happens I’ll do this.

I did make a spindump – would that be helpful / provide similar information?

It would help to know what plugins you’re using. I noticed that lua plugins can do that (loops are not interruptable with <c-c> as vimscript loops are, I think).

I’m pretty sure this problem predates my migration to 0.6 / lua, but it’s hard to remember for sure.

vim.cmd([[
" https://github.com/junegunn/vim-plug/wiki/faq#automatic-installation
if empty(glob('~/.vim/autoload/plug.vim'))
  silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  autocmd VimEnter * PlugInstall | source $MYVIMRC
endif

call plug#begin('~/.vim/bundle')
Plug 'fatih/vim-go', { 'for': 'go', 'do': ':GoUpdateBinaries' }
Plug 'w0rp/ale', { 'for': [ 'bash', 'python', 'go', 'javascript', 'json', 'lua', 'markdown', 'rust', 'sh', 'swift', 'text', 'yaml' ], 'on': '<Plug>(ale_toggle)' }
Plug 'sjl/badwolf'
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'
Plug 'sudar/vim-arduino-syntax', { 'for': ['ino', 'pde'] }
Plug 'junegunn/fzf.vim'
Plug 'rust-lang/rust.vim', { 'for': ['rust'] }
Plug 'vimwiki/vimwiki'

Plug 'neovim/nvim-lspconfig'
Plug 'nvim-lua/completion-nvim'
Plug 'nvim-lua/lsp_extensions.nvim'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
Plug 'nvim-treesitter/playground'

call plug#end()

At least this one is considered deprecated.

Oh bummer, I really liked having an “officially supported” one.

Was just thinking this morning about how this issue seemed to have gone away, then it happened again ¯\_(ツ)_/¯

I don’t have gdb on my M1 Mac, so I tried with lldb:

$ lldb -p 84661
(lldb) process attach --pid 84661
Process 84661 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x00000001ac062270 libsystem_kernel.dylib`__psynch_cvwait + 8
libsystem_kernel.dylib`__psynch_cvwait:
->  0x1ac062270 <+8>:  b.lo   0x1ac062290               ; <+40>
    0x1ac062274 <+12>: pacibsp
    0x1ac062278 <+16>: stp    x29, x30, [sp, #-0x10]!
    0x1ac06227c <+20>: mov    x29, sp
Target 0: (nvim) stopped.
Executable module set to "/opt/homebrew/Cellar/neovim/0.7.2/bin/nvim".
Architecture set to: arm64e-apple-macosx-.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00000001ac062270 libsystem_kernel.dylib`__psynch_cvwait + 8
    frame #1: 0x00000001ac09c83c libsystem_pthread.dylib`_pthread_cond_wait + 1236
    frame #2: 0x000000010116d7d8 libuv.1.dylib`uv_cond_wait + 12
    frame #3: 0x0000000100d91b58 nvim`ui_bridge_suspend + 112
    frame #4: 0x0000000100c47154 nvim`ex_stop + 220
    frame #5: 0x0000000100c3a034 nvim`do_cmdline + 14012
    frame #6: 0x0000000100cce28c nvim`normal_execute + 4792
    frame #7: 0x0000000100d6fd14 nvim`state_enter + 356
    frame #8: 0x0000000100c9aba0 nvim`main + 10676
    frame #9: 0x0000000100fad08c dyld`start + 520

@glacambre Just happened again on my linux x86 machine.

GNU gdb (GDB) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 7581
[New LWP 7588]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
0x00007fd94084b119 in ?? () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007fd94084b119 in ?? () from /usr/lib/libc.so.6
#1  0x00007fd94084d920 in pthread_cond_wait () from /usr/lib/libc.so.6
#2  0x00007fd940bef44e in uv_cond_wait () from /usr/lib/libuv.so.1
#3  0x0000561ba4c4803c in ?? ()
#4  0x0000561ba4a9d43b in ?? ()
#5  0x0000561ba4a8e380 in ?? ()
#6  0x0000561ba4a90815 in do_cmdline ()
#7  0x0000561ba4b447fd in ?? ()
#8  0x0000561ba4c1a73f in state_enter ()
#9  0x0000561ba4b431a9 in normal_enter ()
#10 0x0000561ba4999690 in main ()
(gdb) 

I tried going up and down between a few stack traces but not sure what to do from there.

@n8henrie It looks like you are missing debug symbols, but you’ll need them to debug the problem.

Looking at your lldb backtrace, it looks like neovim is stuck in ui_bridge suspend:

static void ui_bridge_suspend(UI *b)
{
  UIBridgeData *data = (UIBridgeData *)b;
  uv_mutex_lock(&data->mutex);
  UI_BRIDGE_CALL(b, suspend, 1, b);
  data->ready = false;
  // Suspend the main thread until CONTINUE is called by the UI thread.
  while (!data->ready) {
    uv_cond_wait(&data->cond, &data->mutex);
  }
  uv_mutex_unlock(&data->mutex);
}

So the UI thread never wakes up the main thread? So we’d need to know what the UI thread is doing.

Hmmm, I imagine that means I need to build from source?

Maybe, but not necessarily. Some distributions provide debug symbols along their packages. For example, on Debian, there are -dbgsym packages that can be installed alongside the existing package and provide debug symbols.

Hmmm, I don’t see anything obvious for Arch or MacOS (homebrew). Shouldn’t be too tough to compile though.