Subject: Re: bug#11665: kill-buffer gives an error on killing dead buffers

From: martin rudalics <[email-masked]>
Date: Sun, 10 Jun 2012 14:55:34 +0200

> Create a buffer "test.tmp" and create an indirect buffer:
 >
 >    (with-current-buffer (make-indirect-buffer "test.tmp" "test1")
 >      	    (add-hook 'kill-buffer-hook
 >    		      '(lambda ()
 >                             (setq kill-buffer-hook nil)
 >                             (kill-buffer (buffer-base-buffer)))
 >    		      t t))
 >
 > (The above triggers the killing of the base buffer when an indirect
 > buffer is killed)
 >
 > Now, kill the base buffer "test.tmp", which raises:
 >
 >   signal(error ("Buffer #<killed buffer> is not a live buffer"))
 >   error("Buffer %s is not a live buffer" #<killed buffer>)
 >   window-normalize-buffer(#<killed buffer>)
 >   replace-buffer-in-windows(#<killed buffer>)
 >   kill-buffer(#<killed buffer>)
 >   (if (and (boundp (quote sub-kill-buffer-and-its-windows)) sub-kill-buffer-and-its-windows (fboundp (quote kill-buffer-and-its-windows))) (kill-buffer-and-its-windows (current-buffer)) (kill-buffer (current-buffer)))
 >
 >
 > This doesn't occur when killing an indirect buffer.

I don't have `sub-kill-buffer-and-its-windows' so I can't repeat this
easily.  Anyway, here's what I suppose to happen:

Killing "test.tmp" implicitly calls `kill-buffer' on "test1" because
killing a base buffer kills all its indirect buffers.

    Killing "test1" calls `kill-buffer' on "test.tmp" because that's on
    the hook.

       Killing "test.tmp" calls `kill-buffer' on "test1" again.

          Killing "test1" now succeeds and returns.
	
       Killing "test.tmp" now succeeds.

   Killing "test1" now tries to continue with `replace-buffer-in-windows'
   but this fails because the buffer is no more live.

I also suppose that the

 >   kill-buffer(#<killed buffer>)

is a red herring in the sense that `kill-buffer' was actually invoked
with a live buffer but when the trace was printed the buffer was already
dead while `replace-buffer-in-windows' was really called with a dead
buffer as argument.

Basically, I could exit `replace-buffer-in-windows' when the argument
buffer is not live but that's not nice.  So maybe the attached patch is
better.  Can you try it?

martin
*** src/buffer.c	2012-05-29 16:13:38 +0000
--- src/buffer.c	2012-06-10 12:52:57 +0000
***************
*** 1526,1531 ****
--- 1526,1535 ----
        UNGCPRO;
      }

+   /* If killing the indirect buffers has killed our buffer, return.  */
+   if (NILP (BVAR (b, name)))
+     return Qnil;
+ 
    /* Run replace_buffer_in_windows before making another buffer current
       since set-window-buffer-start-and-point will refuse to make another
       buffer current if the selected window does not show the current