To: vim_dev@googlegroups.com Subject: Patch 8.2.0371 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0371 Problem: Crash with combination of terminal popup and autocmd. Solution: Disallow closing a popup that is the current window. Add a check that the current buffer is valid. (closes #5754) Files: src/macros.h, src/buffer.c, src/popupwin.c, src/terminal.c, src/testdir/test_terminal.vim *** ../vim-8.2.0370/src/macros.h 2020-02-28 22:19:38.310023356 +0100 --- src/macros.h 2020-03-11 12:23:55.990247931 +0100 *************** *** 364,371 **** --- 364,374 ---- # define ESTACK_CHECK_SETUP estack_len_before = exestack.ga_len; # define ESTACK_CHECK_NOW if (estack_len_before != exestack.ga_len) \ siemsg("Exestack length expected: %d, actual: %d", estack_len_before, exestack.ga_len); + # define CHECK_CURBUF if (curwin != NULL && curwin->w_buffer != curbuf) \ + iemsg("curbuf != curwin->w_buffer") #else # define ESTACK_CHECK_DECLARATION # define ESTACK_CHECK_SETUP # define ESTACK_CHECK_NOW + # define CHECK_CURBUF #endif *** ../vim-8.2.0370/src/buffer.c 2020-02-08 18:35:12.528045466 +0100 --- src/buffer.c 2020-03-11 07:50:04.683125949 +0100 *************** *** 508,513 **** --- 508,514 ---- int wipe_buf = (action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); int del_buf = (action == DOBUF_DEL || wipe_buf); + CHECK_CURBUF; /* * Force unloading or deleting when 'bufhidden' says so. * The caller must take care of NOT deleting/freeing when 'bufhidden' is *************** *** 530,535 **** --- 531,537 ---- #ifdef FEAT_TERMINAL if (bt_terminal(buf) && (buf->b_nwindows == 1 || del_buf)) { + CHECK_CURBUF; if (term_job_running(buf->b_term)) { if (wipe_buf || unload_buf) *************** *** 554,559 **** --- 556,562 ---- unload_buf = TRUE; wipe_buf = TRUE; } + CHECK_CURBUF; } #endif *************** *** 743,748 **** --- 746,752 ---- if (del_buf) buf->b_p_bl = FALSE; } + // NOTE: at this point "curbuf" may be invalid! } /* *************** *** 933,939 **** --- 937,947 ---- au_pending_free_buf = buf; } else + { vim_free(buf); + if (curbuf == buf) + curbuf = NULL; // make clear it's not to be used + } } /* *** ../vim-8.2.0370/src/popupwin.c 2020-03-06 21:43:14.414246402 +0100 --- src/popupwin.c 2020-03-11 14:03:58.633566371 +0100 *************** *** 2135,2141 **** break; if (owp != NULL) win_enter(owp, FALSE); ! else if (win_valid(prevwin)) win_enter(prevwin, FALSE); else win_enter(firstwin, FALSE); --- 2135,2141 ---- break; if (owp != NULL) win_enter(owp, FALSE); ! else if (win_valid(prevwin) && wp != prevwin) win_enter(prevwin, FALSE); else win_enter(firstwin, FALSE); *************** *** 2147,2157 **** --- 2147,2159 ---- if (wp == curwin && ERROR_IF_POPUP_WINDOW) return; + CHECK_CURBUF; if (wp->w_close_cb.cb_name != NULL) // Careful: This may make "wp" invalid. invoke_popup_callback(wp, arg); popup_close(id); + CHECK_CURBUF; } void *************** *** 2505,2510 **** --- 2507,2517 ---- for (wp = first_popupwin; wp != NULL; prev = wp, wp = wp->w_next) if (wp->w_id == id) { + if (wp == curwin) + { + ERROR_IF_ANY_POPUP_WINDOW; + return; + } if (prev == NULL) first_popupwin = wp->w_next; else *************** *** 2531,2536 **** --- 2538,2548 ---- for (wp = *root; wp != NULL; prev = wp, wp = wp->w_next) if (wp->w_id == id) { + if (wp == curwin) + { + ERROR_IF_ANY_POPUP_WINDOW; + return; + } if (prev == NULL) *root = wp->w_next; else *************** *** 2881,2890 **** { // win_execute() may set "curwin" to a popup window temporarily, but many // commands are disallowed then. When a terminal runs in the popup most ! // things are allowed. if (WIN_IS_POPUP(curwin) # ifdef FEAT_TERMINAL && (also_with_term || curbuf->b_term == NULL) # endif ) { --- 2893,2903 ---- { // win_execute() may set "curwin" to a popup window temporarily, but many // commands are disallowed then. When a terminal runs in the popup most ! // things are allowed. When a terminal is finished it can be closed. if (WIN_IS_POPUP(curwin) # ifdef FEAT_TERMINAL && (also_with_term || curbuf->b_term == NULL) + && !term_is_finished(curbuf) # endif ) { *** ../vim-8.2.0370/src/terminal.c 2020-02-28 22:19:38.314023342 +0100 --- src/terminal.c 2020-03-10 19:53:06.484870815 +0100 *************** *** 382,387 **** --- 382,388 ---- curwin->w_buffer = curbuf; ++curbuf->b_nwindows; } + CHECK_CURBUF; // Wiping out the buffer will also close the window and call // free_terminal(). *** ../vim-8.2.0370/src/testdir/test_terminal.vim 2020-03-03 22:56:36.302382831 +0100 --- src/testdir/test_terminal.vim 2020-03-11 14:15:57.889585751 +0100 *************** *** 2430,2432 **** --- 2430,2456 ---- call assert_equal('', bufname('^$')) call StopShellInTerminal(buf) endfunc + + func Test_term_nasty_callback() + func OpenTerms() + set hidden + let g:buf0 = term_start('sh', #{hidden: 1}) + call popup_create(g:buf0, {}) + let g:buf1 = term_start('sh', #{hidden: 1, term_finish: 'close'}) + call popup_create(g:buf1, {}) + let g:buf2 = term_start(['sh', '-c'], #{curwin: 1, exit_cb: function('TermExit')}) + sleep 100m + call popup_close(win_getid()) + endfunc + func TermExit(...) + call term_sendkeys(bufnr('#'), "exit\") + call popup_close(win_getid()) + endfu + call OpenTerms() + + call term_sendkeys(g:buf0, "exit\") + sleep 50m + exe g:buf0 .. 'bwipe' + set hidden& + endfunc + *** ../vim-8.2.0370/src/version.c 2020-03-11 13:01:36.025436785 +0100 --- src/version.c 2020-03-11 14:16:19.989463949 +0100 *************** *** 740,741 **** --- 740,743 ---- { /* Add new patch number below this line */ + /**/ + 371, /**/ -- hundred-and-one symptoms of being an internet addict: 225. You sign up for free subscriptions for all the computer magazines /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///