comparison src/buffer.c @ 23624:f9d02c83f306 v8.2.2354

patch 8.2.2354: crash with a weird combination of autocommands Commit: https://github.com/vim/vim/commit/797e63b9f2baa1853e7063aac478d663cd02f207 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Jan 15 16:22:52 2021 +0100 patch 8.2.2354: crash with a weird combination of autocommands Problem: Crash with a weird combination of autocommands. Solution: Increment b_nwindows when needed. (closes https://github.com/vim/vim/issues/7674)
author Bram Moolenaar <Bram@vim.org>
date Fri, 15 Jan 2021 16:30:04 +0100
parents 9a5f12b36273
children 29eccef07e2f
comparison
equal deleted inserted replaced
23623:905ba483e284 23624:f9d02c83f306
490 * When "abort_if_last" is TRUE then do not close the buffer if autocommands 490 * When "abort_if_last" is TRUE then do not close the buffer if autocommands
491 * cause there to be only one window with this buffer. e.g. when ":quit" is 491 * cause there to be only one window with this buffer. e.g. when ":quit" is
492 * supposed to close the window but autocommands close all other windows. 492 * supposed to close the window but autocommands close all other windows.
493 * 493 *
494 * When "ignore_abort" is TRUE don't abort even when aborting() returns TRUE. 494 * When "ignore_abort" is TRUE don't abort even when aborting() returns TRUE.
495 */ 495 *
496 void 496 * Return TRUE when we got to the end and b_nwindows was decremented.
497 */
498 int
497 close_buffer( 499 close_buffer(
498 win_T *win, // if not NULL, set b_last_cursor 500 win_T *win, // if not NULL, set b_last_cursor
499 buf_T *buf, 501 buf_T *buf,
500 int action, 502 int action,
501 int abort_if_last, 503 int abort_if_last,
538 if (term_job_running(buf->b_term)) 540 if (term_job_running(buf->b_term))
539 { 541 {
540 if (wipe_buf || unload_buf) 542 if (wipe_buf || unload_buf)
541 { 543 {
542 if (!can_unload_buffer(buf)) 544 if (!can_unload_buffer(buf))
543 return; 545 return FALSE;
544 546
545 // Wiping out or unloading a terminal buffer kills the job. 547 // Wiping out or unloading a terminal buffer kills the job.
546 free_terminal(buf); 548 free_terminal(buf);
547 } 549 }
548 else 550 else
569 #endif 571 #endif
570 572
571 // Disallow deleting the buffer when it is locked (already being closed or 573 // Disallow deleting the buffer when it is locked (already being closed or
572 // halfway a command that relies on it). Unloading is allowed. 574 // halfway a command that relies on it). Unloading is allowed.
573 if ((del_buf || wipe_buf) && !can_unload_buffer(buf)) 575 if ((del_buf || wipe_buf) && !can_unload_buffer(buf))
574 return; 576 return FALSE;
575 577
576 // check no autocommands closed the window 578 // check no autocommands closed the window
577 if (win != NULL && win_valid_any_tab(win)) 579 if (win != NULL && win_valid_any_tab(win))
578 { 580 {
579 // Set b_last_cursor when closing the last window for the buffer. 581 // Set b_last_cursor when closing the last window for the buffer.
598 && !bufref_valid(&bufref)) 600 && !bufref_valid(&bufref))
599 { 601 {
600 // Autocommands deleted the buffer. 602 // Autocommands deleted the buffer.
601 aucmd_abort: 603 aucmd_abort:
602 emsg(_(e_auabort)); 604 emsg(_(e_auabort));
603 return; 605 return FALSE;
604 } 606 }
605 --buf->b_locked; 607 --buf->b_locked;
606 if (abort_if_last && one_window()) 608 if (abort_if_last && one_window())
607 // Autocommands made this the only window. 609 // Autocommands made this the only window.
608 goto aucmd_abort; 610 goto aucmd_abort;
623 goto aucmd_abort; 625 goto aucmd_abort;
624 } 626 }
625 #ifdef FEAT_EVAL 627 #ifdef FEAT_EVAL
626 // autocmds may abort script processing 628 // autocmds may abort script processing
627 if (!ignore_abort && aborting()) 629 if (!ignore_abort && aborting())
628 return; 630 return FALSE;
629 #endif 631 #endif
630 } 632 }
631 633
632 // If the buffer was in curwin and the window has changed, go back to that 634 // If the buffer was in curwin and the window has changed, go back to that
633 // window, if it still exists. This avoids that ":edit x" triggering a 635 // window, if it still exists. This avoids that ":edit x" triggering a
651 #endif 653 #endif
652 654
653 // Return when a window is displaying the buffer or when it's not 655 // Return when a window is displaying the buffer or when it's not
654 // unloaded. 656 // unloaded.
655 if (buf->b_nwindows > 0 || !unload_buf) 657 if (buf->b_nwindows > 0 || !unload_buf)
656 return; 658 return FALSE;
657 659
658 // Always remove the buffer when there is no file name. 660 // Always remove the buffer when there is no file name.
659 if (buf->b_ffname == NULL) 661 if (buf->b_ffname == NULL)
660 del_buf = TRUE; 662 del_buf = TRUE;
661 663
681 + (wipe_buf ? BFA_WIPE : 0) 683 + (wipe_buf ? BFA_WIPE : 0)
682 + (ignore_abort ? BFA_IGNORE_ABORT : 0)); 684 + (ignore_abort ? BFA_IGNORE_ABORT : 0));
683 685
684 // Autocommands may have deleted the buffer. 686 // Autocommands may have deleted the buffer.
685 if (!bufref_valid(&bufref)) 687 if (!bufref_valid(&bufref))
686 return; 688 return FALSE;
687 #ifdef FEAT_EVAL 689 #ifdef FEAT_EVAL
688 // autocmds may abort script processing 690 // autocmds may abort script processing
689 if (!ignore_abort && aborting()) 691 if (!ignore_abort && aborting())
690 return; 692 return FALSE;
691 #endif 693 #endif
692 694
693 /* 695 /*
694 * It's possible that autocommands change curbuf to the one being deleted. 696 * It's possible that autocommands change curbuf to the one being deleted.
695 * This might cause the previous curbuf to be deleted unexpectedly. But 697 * This might cause the previous curbuf to be deleted unexpectedly. But
696 * in some cases it's OK to delete the curbuf, because a new one is 698 * in some cases it's OK to delete the curbuf, because a new one is
697 * obtained anyway. Therefore only return if curbuf changed to the 699 * obtained anyway. Therefore only return if curbuf changed to the
698 * deleted buffer. 700 * deleted buffer.
699 */ 701 */
700 if (buf == curbuf && !is_curbuf) 702 if (buf == curbuf && !is_curbuf)
701 return; 703 return FALSE;
702 704
703 if (win_valid_any_tab(win) && win->w_buffer == buf) 705 if (win_valid_any_tab(win) && win->w_buffer == buf)
704 win->w_buffer = NULL; // make sure we don't use the buffer now 706 win->w_buffer = NULL; // make sure we don't use the buffer now
705 707
706 // Autocommands may have opened or closed windows for this buffer. 708 // Autocommands may have opened or closed windows for this buffer.
753 buf_clear_file(buf); 755 buf_clear_file(buf);
754 if (del_buf) 756 if (del_buf)
755 buf->b_p_bl = FALSE; 757 buf->b_p_bl = FALSE;
756 } 758 }
757 // NOTE: at this point "curbuf" may be invalid! 759 // NOTE: at this point "curbuf" may be invalid!
760 return TRUE;
758 } 761 }
759 762
760 /* 763 /*
761 * Make buffer not contain a file. 764 * Make buffer not contain a file.
762 */ 765 */