Mercurial > vim
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 */ |