Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0a0c349

Browse files
authored
fix(events): crash on WinScrolled#35995
Problem: apply_autocmds function can free both buf_T and win_T pointersSolution: instead retain winids for WinResized and WinScrolledautocmds and use curbuf pointer, which is consistent with other usesof apply_autocmds function
1 parent87bd16e commit0a0c349

File tree

2 files changed

+69
-7
lines changed

2 files changed

+69
-7
lines changed

‎src/nvim/window.c‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5788,17 +5788,30 @@ void may_trigger_win_scrolled_resized(void)
57885788

57895789
recursive= true;
57905790

5791+
// Save window info before autocmds since they can free windows
5792+
charresize_winid[NUMBUFLEN];
5793+
bufref_Tresize_bufref;
5794+
if (trigger_resize) {
5795+
vim_snprintf(resize_winid,sizeof(resize_winid),"%d",first_size_win->handle);
5796+
set_bufref(&resize_bufref,first_size_win->w_buffer);
5797+
}
5798+
5799+
charscroll_winid[NUMBUFLEN];
5800+
bufref_Tscroll_bufref;
5801+
if (trigger_scroll) {
5802+
vim_snprintf(scroll_winid,sizeof(scroll_winid),"%d",first_scroll_win->handle);
5803+
set_bufref(&scroll_bufref,first_scroll_win->w_buffer);
5804+
}
5805+
57915806
// If both are to be triggered do WinResized first.
57925807
if (trigger_resize) {
57935808
save_v_event_Tsave_v_event;
57945809
dict_T*v_event=get_v_event(&save_v_event);
57955810

57965811
if (tv_dict_add_list(v_event,S_LEN("windows"),windows_list)==OK) {
57975812
tv_dict_set_keys_readonly(v_event);
5798-
5799-
charwinid[NUMBUFLEN];
5800-
vim_snprintf(winid,sizeof(winid),"%d",first_size_win->handle);
5801-
apply_autocmds(EVENT_WINRESIZED,winid,winid, false,first_size_win->w_buffer);
5813+
buf_T*buf=bufref_valid(&resize_bufref) ?resize_bufref.br_buf :curbuf;
5814+
apply_autocmds(EVENT_WINRESIZED,resize_winid,resize_winid, false,buf);
58025815
}
58035816
restore_v_event(v_event,&save_v_event);
58045817
}
@@ -5812,9 +5825,8 @@ void may_trigger_win_scrolled_resized(void)
58125825
tv_dict_set_keys_readonly(v_event);
58135826
tv_dict_unref(scroll_dict);
58145827

5815-
charwinid[NUMBUFLEN];
5816-
vim_snprintf(winid,sizeof(winid),"%d",first_scroll_win->handle);
5817-
apply_autocmds(EVENT_WINSCROLLED,winid,winid, false,first_scroll_win->w_buffer);
5828+
buf_T*buf=bufref_valid(&scroll_bufref) ?scroll_bufref.br_buf :curbuf;
5829+
apply_autocmds(EVENT_WINSCROLLED,scroll_winid,scroll_winid, false,buf);
58185830

58195831
restore_v_event(v_event,&save_v_event);
58205832
}

‎test/functional/autocmd/win_scrolled_resized_spec.lua‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,54 @@ describe('WinScrolled', function()
349349
[winid_str]= {leftcol=0,topline=-3,topfill=0,width=0,height=0,skipcol=0 },
350350
},eval('g:v_event'))
351351
end)
352+
353+
it('does not crash when WinResized closes popup before WinScrolled #35803',function()
354+
exec([[
355+
set scrolloff=0
356+
call setline(1, range(1, 100))
357+
358+
" Create first popup window (will be resized and closed)
359+
let buf1 = nvim_create_buf(v:false, v:true)
360+
call nvim_buf_set_lines(buf1, 0, -1, v:false, map(range(1, 50), 'string(v:val)'))
361+
let popup1 = nvim_open_win(buf1, v:false, {
362+
\ 'relative': 'editor',
363+
\ 'width': 20,
364+
\ 'height': 5,
365+
\ 'col': 10,
366+
\ 'row': 5
367+
\ })
368+
369+
" Create second popup window (will be scrolled)
370+
let buf2 = nvim_create_buf(v:false, v:true)
371+
call nvim_buf_set_lines(buf2, 0, -1, v:false, map(range(1, 50), 'string(v:val)'))
372+
let popup2 = nvim_open_win(buf2, v:false, {
373+
\ 'relative': 'editor',
374+
\ 'width': 20,
375+
\ 'height': 5,
376+
\ 'col': 35,
377+
\ 'row': 5
378+
\ })
379+
380+
let g:resized = 0
381+
let g:scrolled = 0
382+
383+
" WinResized autocmd resizes and closes the first popup
384+
autocmd WinResized * let g:resized += 1 | call nvim_win_set_height(popup1, 10) | call nvim_win_close(popup1, v:true)
385+
" WinScrolled autocmd scrolls the second popup
386+
autocmd WinScrolled * let g:scrolled += 1 | call nvim_win_call(popup2, {-> execute('normal! \<C-E>')})
387+
]])
388+
eq(0,eval('g:resized'))
389+
eq(0,eval('g:scrolled'))
390+
391+
-- Trigger a resize on popup1, which will close it
392+
-- This should trigger WinResized (which closes popup1) and WinScrolled (which scrolls popup2)
393+
-- Before the fix, WinScrolled would use the freed pointer causing a crash
394+
api.nvim_win_set_height(eval('popup1'),8)
395+
396+
-- The key is that it should not crash when WinResized closes a window
397+
-- that WinScrolled might have referenced via a stale buf_T pointer
398+
assert_alive()
399+
-- Verify autocmds were actually triggered
400+
eq(1,eval('g:resized > 0'))
401+
end)
352402
end)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp