bug#81504: [PATCH] Restore current buffer after clone-indirect-buffer-hook errors

Donjuanplatinum via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <[email protected]>
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
Version: 31.0.50
Base-Commit: 810e9d675ba484dabade1a9f30201d2848c5e2ea

In `make-indirect-buffer` with clone argument, if
`clone-indirect-buffer-hook` return an error, `current-buffer` will not
be restored.

To make the error in emacs -Q:


   (progn
      (generate-new-buffer "base")
      (with-current-buffer "base" (insert "text"))
      (set-buffer "base")
      (let ((clone-indirect-buffer-hook
             (list (lambda () (error "hook error")))))
        (condition-case nil
            (make-indirect-buffer "base" "ind" t)
          (error nil)))
      (buffer-name (current-buffer)))

Expected: "base"
But get: "ind"

The Clone path in Fmake_indirect_buffer use set_buffer_internal_1 to
restore the current-buffer, but when clone-indirect-buffer-hook return
an error, it will skip the set_buffer_internal_1.

The attached patch replaces it with record_unwind_current_buffer so that
it will following the standard specpdl pattern to restore the current-buffer.
0001-Restore-current-buffer-after-clone-indirect-buffer-h.patch (text/x-patch, 3.2 KB)
From 89ce33acdd96a76f6efb831183349ea7d3be406f Mon Sep 17 00:00:00 2001
From: Donjuanplatinum <[email protected]>
Date: Tue, 28 Jul 2026 01:25:56 +0800
Subject: [PATCH] Restore current buffer after clone-indirect-buffer-hook
 errors

When the CLONE argument is non-nil, Fmake_indirect_buffer switches to
the new indirect buffer and runs clone-indirect-buffer-hook. If the hook
return an error, the set_buffer_internal_1 restore is skipped, so
current_buffer pointing to the indirect buffer.

Use record_unwind_current_buffer to ensure the original buffer can be
restored in normal and error paths.

* src/buffer.c (Fmake_indirect_buffer): Replace set_buffer_internal_1 to
specpdl unwind in the clone path.

* test/src/buffer-tests.el (test-make-indirect-buffer-clone-hook): Add
this condition test.
---
 src/buffer.c             |  8 ++++++--
 test/src/buffer-tests.el | 17 +++++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/buffer.c b/src/buffer.c
index 0a2bff27c11..423c0ce7905 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -937,7 +937,9 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
     }
   else
     {
-      struct buffer *old_b = current_buffer;
+      /* Arrange for the current buffer to be restored later,
+	 even if an exit occurs. */
+      specpdl_ref count = SPECPDL_INDEX ();
 
       clone_per_buffer_values (b->base_buffer, b);
       bset_filename (b, Qnil);
@@ -946,6 +948,7 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
       bset_backed_up (b, Qnil);
       bset_local_minor_modes (b, Qnil);
       bset_auto_save_file_name (b, Qnil);
+      record_unwind_current_buffer ();
       set_buffer_internal_1 (b);
       Fset (Qbuffer_save_without_query, Qnil);
       Fset (Qbuffer_file_number, Qnil);
@@ -955,7 +958,8 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
 	 variable copies for list variables that might be mangled due
 	 to destructive operations in the indirect buffer. */
       run_hook (Qclone_indirect_buffer_hook);
-      set_buffer_internal_1 (old_b);
+      /* Restore the original buffer.  */
+      unbind_to (count, Qnil);
     }
 
   run_buffer_list_update_hook (b);
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index 3fae18011fb..fc6ba43b3d7 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -1478,6 +1478,23 @@ test-make-indirect-buffer-1
           (kill-buffer indirect))))))
 
 
+(ert-deftest test-make-indirect-buffer-clone-hook ()
+  (let ((base-buf (generate-new-buffer "base")))
+    (unwind-protect
+        (progn
+          (with-current-buffer base-buf
+            (insert "sample text"))
+          (set-buffer base-buf)
+          (let ((clone-indirect-buffer-hook
+                 (list (lambda ()
+                         (error "clone hook error")))))
+            (should-error
+             (make-indirect-buffer base-buf "indirect" t)))
+          (should (eq (current-buffer) base-buf)))
+      (ignore-errors (kill-buffer "indirect"))
+      (when (buffer-live-p base-buf)
+        (kill-buffer base-buf)))))
+
 
 ;; +==========================================================================+
 ;; | buffer-swap-text
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.