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

Neovim segfaults on termux when dismissing and raising onscreen keyboard #22278

Open
beelzebielsk opened this issue Feb 16, 2023 · 8 comments
Open
Labels
bug-crash issue reporting a crash or segfault has:backtrace issue contains a stacktrace/ASAN log has:repro issue contains minimal reproducing steps ui
Milestone

Comments

@beelzebielsk
Copy link

beelzebielsk commented Feb 16, 2023

Describe the bug

If I open a particular file in neovim, scroll to the very last line, dismiss the onscreen keyboard, and then pull the keyboard back up again, neovim segfaults. Consistently. I eliminated my configs as a cause.

I haven't been able to reproduce this on a PC, because I don't know what would have the equivalent effect of raising and lowering a onscreen keyboard. I don't yet know if neovim or termux or both are responsible.

It looks like the bug is caused by the last line being wrapped and partially offscreen. So your terminal dimensions have to allow that.

Steps to reproduce

Use the onscreen keyboard for this.

  1. Get termux's dimensions to one of 35 cols × 14 lines, or 33 cols × 13 lines. This is with the keyboard open. There may be other dimensions which cause the segfault, but I confirmed these.
  2. Paste into termux: curl -s https://termbin.com/2q2fq | nvim -u NONE -c "set linebreak"
  3. Type G$ (move the cursor to the end of the last line in the file)
  4. Dismiss the onscreen keyboard (open the side menu and hit "keyboard")
  5. Bring the onscreen keyboard back up (repeat prior step). Neovim should segfault immediately.

Expected behavior

It shouldn't segfault.

Neovim version (nvim -v)

0.8.3

Vim (not Nvim) behaves the same?

no, vim 9.0

Operating system/version

Android 10

Terminal name/version

termux 0.118.0

$TERM environment variable

xterm-256color

Installation

system package manager (the pkg command in termux)

EDIT: Added terminal sizes to "steps to reproduce".

@beelzebielsk beelzebielsk added the bug issues reporting wrong behavior label Feb 16, 2023
@beelzebielsk
Copy link
Author

The terminal dimensions where I get segfaults are 35 cols × 14 lines, or 33 cols × 13 lines.

@zeertzjq
Copy link
Member

zeertzjq commented Feb 16, 2023

Backtrace:

                #0  0x000055bc86876f4a ui_comp_grid_scroll (nvim + 0x2baf4a)
                #1  0x000055bc86876fcc ui_call_grid_scroll (nvim + 0x2bafcc)
                #2  0x000055bc8673a938 grid_del_lines (nvim + 0x17e938)
                #3  0x000055bc86813124 win_scroll_lines (nvim + 0x257124)
                #4  0x000055bc8679c721 curs_columns (nvim + 0x1e0721)
                #5  0x000055bc8679c824 validate_cursor (nvim + 0x1e0824)
                #6  0x000055bc8679c15f update_topline (nvim + 0x1e015f)
                #7  0x000055bc866aa071 screen_resize (nvim + 0xee071)
                #8  0x000055bc868727f9 ui_refresh (nvim + 0x2b67f9)
                #9  0x000055bc86665f14 nvim_ui_try_resize (nvim + 0xa9f14)
                #10 0x000055bc8665ccfc handle_nvim_ui_try_resize (nvim + 0xa0cfc)
                #11 0x000055bc867a06bd request_event (nvim + 0x1e46bd)
                #12 0x000055bc866f3ec0 multiqueue_oneshot_event (nvim + 0x137ec0)
                #13 0x000055bc868444fd state_handle_k_event (nvim + 0x2884fd)
                #14 0x000055bc867acfc6 nv_event (nvim + 0x1f0fc6)
                #15 0x000055bc867a99f6 normal_execute (nvim + 0x1ed9f6)
                #16 0x000055bc86844394 state_enter (nvim + 0x288394)
                #17 0x000055bc867a1fec normal_enter (nvim + 0x1e5fec)
                #18 0x000055bc86633abf main (nvim + 0x77abf)
                #19 0x00007f13ef153790 n/a (libc.so.6 + 0x23790)
                #20 0x00007f13ef15384a __libc_start_main (libc.so.6 + 0x2384a)
                #21 0x000055bc8662f045 _start (nvim + 0x73045)

ASAN log:

=================================================================
==53977==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60b000002518 at pc 0x56027b17fb23 bp 0x7ffed08f52d0 sp 0x7ffed08f52c8
READ of size 8 at 0x60b000002518 thread T0
    #0 0x56027b17fb22 in grid_del_lines **/src/nvim/grid.c:893:45
    #1 0x56027b9983bf in win_scroll_lines **/src/nvim/screen.c:405:5
    #2 0x56027b553938 in curs_columns **/src/nvim/move.c:910:5
    #3 0x56027b549b46 in validate_cursor **/src/nvim/move.c:525:5
    #4 0x56027b53cdb1 in update_topline **/src/nvim/move.c:338:7
    #5 0x56027abfe25f in screen_resize **/src/nvim/drawscreen.c:358:9
    #6 0x56027bdba12b in ui_refresh **/src/nvim/ui.c:215:3
    #7 0x56027a96cba6 in nvim_ui_try_resize **/src/nvim/api/ui.c:279:3
    #8 0x56027a8e9243 in handle_nvim_ui_try_resize **/build/src/nvim/auto/api/private/dispatch_wrappers.generated.h:4266:3
    #9 0x56027b5897aa in request_event **/src/nvim/msgpack_rpc/channel.c:359:19
    #10 0x56027af09497 in multiqueue_oneshot_event **/src/nvim/event/multiqueue.c:274:7
    #11 0x56027bbf2d79 in state_handle_k_event **/src/nvim/state.c:117:7
    #12 0x56027b61bce9 in nv_event **/src/nvim/normal.c:6621:3
    #13 0x56027b5e1038 in normal_execute **/src/nvim/normal.c:1200:3
    #14 0x56027bbf2b47 in state_enter **/src/nvim/state.c:99:26
    #15 0x56027b5c48b0 in normal_enter **/src/nvim/normal.c:498:3
    #16 0x56027a74ddaa in main **/src/nvim/main.c:633:3
    #17 0x7f99eaa9178f  (/usr/lib/libc.so.6+0x2378f) (BuildId: 4a4bec3d95a1804443e852958fe59ed461135ce9)
    #18 0x7f99eaa91849 in __libc_start_main (/usr/lib/libc.so.6+0x23849) (BuildId: 4a4bec3d95a1804443e852958fe59ed461135ce9)
    #19 0x56027a64dd54 in _start (**/build/bin/nvim+0xb93d54) (BuildId: f237ce6975decc426a607765962213e4036271e7)

0x60b000002518 is located 0 bytes to the right of 104-byte region [0x60b0000024b0,0x60b000002518)
allocated by thread T0 here:
    #0 0x56027a7052e9 in malloc (**/build/bin/nvim+0xc4b2e9) (BuildId: f237ce6975decc426a607765962213e4036271e7)
    #1 0x56027b4b8366 in try_malloc **/src/nvim/memory.c:88:15
    #2 0x56027b4b853c in xmalloc **/src/nvim/memory.c:122:15
    #3 0x56027b178201 in grid_alloc **/src/nvim/grid.c:665:21
    #4 0x56027abfbe07 in default_grid_alloc **/src/nvim/drawscreen.c:186:3
    #5 0x56027abfd9c3 in screen_resize **/src/nvim/drawscreen.c:293:10
    #6 0x56027bdba12b in ui_refresh **/src/nvim/ui.c:215:3
    #7 0x56027a96cba6 in nvim_ui_try_resize **/src/nvim/api/ui.c:279:3
    #8 0x56027a8e9243 in handle_nvim_ui_try_resize **/build/src/nvim/auto/api/private/dispatch_wrappers.generated.h:4266:3
    #9 0x56027b5897aa in request_event **/src/nvim/msgpack_rpc/channel.c:359:19
    #10 0x56027af09497 in multiqueue_oneshot_event **/src/nvim/event/multiqueue.c:274:7
    #11 0x56027bbf2d79 in state_handle_k_event **/src/nvim/state.c:117:7
    #12 0x56027b61bce9 in nv_event **/src/nvim/normal.c:6621:3
    #13 0x56027b5e1038 in normal_execute **/src/nvim/normal.c:1200:3
    #14 0x56027bbf2b47 in state_enter **/src/nvim/state.c:99:26
    #15 0x56027b5c48b0 in normal_enter **/src/nvim/normal.c:498:3
    #16 0x56027a74ddaa in main **/src/nvim/main.c:633:3
    #17 0x7f99eaa9178f  (/usr/lib/libc.so.6+0x2378f) (BuildId: 4a4bec3d95a1804443e852958fe59ed461135ce9)

SUMMARY: AddressSanitizer: heap-buffer-overflow **/src/nvim/grid.c:893:45 in grid_del_lines
Shadow bytes around the buggy address:
  0x0c167fff8450: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c167fff8460: fd fd fa fa fa fa fa fa fa fa fd fd fd fd fd fd
  0x0c167fff8470: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
  0x0c167fff8480: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa
  0x0c167fff8490: fa fa fa fa fa fa 00 00 00 00 00 00 00 00 00 00
=>0x0c167fff84a0: 00 00 00[fa]fa fa fa fa fa fa fa fa 00 00 00 00
  0x0c167fff84b0: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa
  0x0c167fff84c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff84d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff84e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff84f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==53977==ABORTING

@zeertzjq zeertzjq added ui has:backtrace issue contains a stacktrace/ASAN log bug-crash issue reporting a crash or segfault and removed bug issues reporting wrong behavior labels Feb 16, 2023
@zeertzjq
Copy link
Member

Script to reproduce:

vim.fn.termopen({ vim.v.progpath, '-u', 'NONE', '-i', 'NONE', '-c', 'set linebreak' })
vim.defer_fn(function()
  vim.fn.jobresize(vim.bo.channel, 35, 14)
  vim.defer_fn(function()
    vim.fn.chansend(vim.bo.channel, 'i' .. [[
x xxx xxxxxxxx xx xxx xxx xxxxxx xxxx x xxxxx xxx xxxxxxx x xxx xxxx xxxxxx xxx xxxxxxxxxx xxxxx xxxxx xx xxxxxx xxx xx xxxxxx

xxxxx xxxxx xxxxx xx xxxxx xxxxxx xx xxxxx xxxxxxx xxx xxxxxx xx xxxxx xxxx xxxx xxxxxx xxxx xxxx xxxxxx xx xxxxxx xxxx xx xxx xxxx xxxxx xxxxx xxxx xxxxx xxxxxxxx xx xx xxxxx xxxx xxxxx xxxx xxxxxxxxx xx xxxx xxx xxxxx xxx xxxx xxx xxxxx xxxx xx xxxxxx xxx xxxx xxxx xxx xxxx xxxx xx xxxx xxxxx x xxxx xxx xxxxx xxxxxxxxxxxxx x xxxxxxxxxxxxxxx xxxxxxx x xxxxx xxxxx x xxx xxxxxx xx xxxxxxxx xxxx xxxxx]] .. '\027')
    vim.defer_fn(function()
      vim.fn.jobresize(vim.bo.channel, 35, 21)
      vim.defer_fn(function()
        vim.fn.jobresize(vim.bo.channel, 35, 13)
      end, 1000)
    end, 1000)
  end, 1000)
end, 1000)

@zeertzjq zeertzjq added the has:repro issue contains minimal reproducing steps label Feb 16, 2023
@zeertzjq
Copy link
Member

This seems to fix the problem:

diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 0ac522059..f392477f4 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -232,6 +232,7 @@ void screenclear(void)
     if (wp->w_floating) {
       wp->w_redr_type = UPD_CLEAR;
     }
+    win_grid_alloc(wp);
   }
   if (must_redraw == UPD_CLEAR) {
     must_redraw = UPD_NOT_VALID;  // no need to clear again

@zeertzjq
Copy link
Member

Test case:

it('', function()
  screen:try_resize(35, 14)
  command('set laststatus=2 linebreak')
  insert([[
    x xxx xxxxxxxx xx xxx xxx xxxxxx xxxx x xxxxx xxx xxxxxxx x xxx xxxx xxxxxx xxx xxxxxxxxxx xxxxx xxxxx xx xxxxxx xxx xx xxxxxx

    xxxxx xxxxx xxxxx xx xxxxx xxxxxx xx xxxxx xxxxxxx xxx xxxxxx xx xxxxx xxxx xxxx xxxxxx xxxx xxxx xxxxxx xx xxxxxx xxxx xx xxx xxxx xxxxx xxxxx xxxx xxxxx xxxxxxxx xx xx xxxxx xxxx xxxxx xxxx xxxxxxxxx xx xxxx xxx xxxxx xxx xxxx xxx xxxxx xxxx xx xxxxxx xxx xxxx xxxx xxx xxxx xxxx xx xxxx xxxxx x xxxx xxx xxxxx xxxxxxxxxxxxx x xxxxxxxxxxxxxxx xxxxxxx x xxxxx xxxxx x xxx xxxxxx xx xxxxxxxx xxxx xxxxx]])
  screen:try_resize(35, 21)
  screen:try_resize(35, 13)
  assert_alive()
end)

@zeertzjq
Copy link
Member

The solution above doesn't work for the case where there is a more prompt:

vim.fn.termopen({ vim.v.progpath, '-u', 'NONE', '-i', 'NONE', '-c', 'set linebreak' })
vim.defer_fn(function()
  vim.fn.jobresize(vim.bo.channel, 35, 14)
  vim.defer_fn(function()
    vim.fn.chansend(vim.bo.channel, 'i' .. [[
x xxx xxxxxxxx xx xxx xxx xxxxxx xxxx x xxxxx xxx xxxxxxx x xxx xxxx xxxxxx xxx xxxxxxxxxx xxxxx xxxxx xx xxxxxx xxx xx xxxxxx

xxxxx xxxxx xxxxx xx xxxxx xxxxxx xx xxxxx xxxxxxx xxx xxxxxx xx xxxxx xxxx xxxx xxxxxx xxxx xxxx xxxxxx xx xxxxxx xxxx xx xxx xxxx xxxxx xxxxx xxxx xxxxx xxxxxxxx xx xx xxxxx xxxx xxxxx xxxx xxxxxxxxx xx xxxx xxx xxxxx xxx xxxx xxx xxxxx xxxx xx xxxxxx xxx xxxx xxxx xxx xxxx xxxx xx xxxx xxxxx x xxxx xxx xxxxx xxxxxxxxxxxxx x xxxxxxxxxxxxxxx xxxxxxx x xxxxx xxxxx x xxx xxxxxx xx xxxxxxxx xxxx xxxxx]] .. '\027')
    vim.defer_fn(function()
      vim.fn.jobresize(vim.bo.channel, 35, 21)
      vim.defer_fn(function()
        vim.fn.chansend(vim.bo.channel, ':hi\r')
        vim.defer_fn(function()
          vim.fn.jobresize(vim.bo.channel, 35, 13)
          vim.defer_fn(function()
            vim.fn.chansend(vim.bo.channel, 'q')
          end, 1000)
        end, 1000)
      end, 1000)
    end, 1000)
  end, 1000)
end, 1000)

@zeertzjq
Copy link
Member

This fixes the case above:

diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 0ac522059..3760e4256 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -306,6 +306,10 @@ void screen_resize(int width, int height)
 
     RedrawingDisabled--;
 
+    FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+      win_grid_alloc(wp);
+    }
+
     // Do not apply autocommands more than 3 times to avoid an endless loop
     // in case applying autocommands always changes Rows or Columns.
     if (++retry_count > 3) {

@zeertzjq
Copy link
Member

This crash can also apply to windows in another tabpage:

it('', function()
  screen:try_resize(35, 14)
  command('set laststatus=2 linebreak')
  insert([[
    x xxx xxxxxxxx xx xxx xxx xxxxxx xxxx x xxxxx xxx xxxxxxx x xxx xxxx xxxxxx xxx xxxxxxxxxx xxxxx xxxxx xx xxxxxx xxx xx xxxxxx

    xxxxx xxxxx xxxxx xx xxxxx xxxxxx xx xxxxx xxxxxxx xxx xxxxxx xx xxxxx xxxx xxxx xxxxxx xxxx xxxx xxxxxx xx xxxxxx xxxx xx xxx xxxx xxxxx xxxxx xxxx xxxxx xxxxxxxx xx xx xxxxx xxxx xxxxx xxxx xxxxxxxxx xx xxxx xxx xxxxx xxx xxxx xxx xxxxx xxxx xx xxxxxx xxx xxxx xxxx xxx xxxx xxxx xx xxxx xxxxx x xxxx xxx xxxxx xxxxxxxxxxxxx x xxxxxxxxxxxxxxx xxxxxxx x xxxxx xxxxx x xxx xxxxxx xx xxxxxxxx xxxx xxxxx]])
  screen:try_resize(35, 21)
  command('tabnew')
  screen:try_resize(35, 13)
  exec_lua([[
    vim.cmd.tabprev()
    vim.wo.signcolumn = 'yes'
  ]])
  assert_alive()
end)

So the fix above isn't the correct fix either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug-crash issue reporting a crash or segfault has:backtrace issue contains a stacktrace/ASAN log has:repro issue contains minimal reproducing steps ui
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants