Subject: bug#891: 23.0.60; Emacs aborts after buffer-swap-text

From: Stefan Monnier <[email-masked]>
Date: Thu, 04 Sep 2008 23:52:45 -0400

> 1. emacs -Q
> 2. Load the library tabbar.el, available from
> http://emhacks.cvs.sourceforge.net/emhacks/emhacks/tabbar.el?revision=1.69&view=markup
> 3. M-x tabbar-mode
> 4. M-: (buffer-swap-text (get-buffer "*Messages*"))
> 5. C-c C-right (tabbar-forward)
>    ==> Emacs aborts

> The full backtrace is below.  According to the Lisp backtrace, the abort
> occurs during or after switch-to-buffer.  Yet typing C-x b after step 4
> above does not make Emacs abort.  Moreover, when I directly call any of
> the tabbar.el functions listed in the backtrace and step through them
> with edebug, this also fails to make Emacs abort.  Yet the above recipe
> is reliably reproducible.  

> (Since the abort occurs in unshow_buffer, my guess, based on a comment
> at line 8314 of xdisp.c, is that switch-to-buffer needs to have
> something like the code in with_echo_area_buffer that changes w->pointm.
> I guess this would go after the call to Fset_buffer in switch-to-buffer,
> but I don't know how to write the code.)

Does the patch below fix the crash you see?

        Stefan

=== modified file 'src/buffer.c'
--- src/buffer.c	2008-08-29 15:11:08 +0000
+++ src/buffer.c	2008-09-05 03:51:15 +0000
@@ -2250,6 +2250,27 @@
       if (m->buffer == current_buffer)
 	m->buffer = other_buffer;
   }
+  /* Some of the C code expects that w->buffer == w->pointm->buffer.
+     So since we just swapped the markers between the two buffers, we need
+     to undo the effect of this swap for window markers.  */
+  {
+    Lisp_Object w = Fselected_window (), ws = Qnil;
+    Lisp_Object buf1, buf2;
+    XSETBUFFER (buf1, current_buffer); XSETBUFFER (buf2, other_buffer);
+
+    while (NILP (Fmemq (w, ws)))
+      {
+	ws = Fcons (w, ws);
+	if ((EQ (XWINDOW (w)->buffer, buf1)
+	     || EQ (XWINDOW (w)->buffer, buf2))
+	    && MARKERP (XWINDOW (w)->pointm))
+	  Fset_marker (XWINDOW (w)->pointm,
+		       make_number (BUF_BEGV (XBUFFER (XWINDOW (w)->buffer))),
+		       XWINDOW (w)->buffer);
+	w = Fnext_window (w, Qt, Qt);
+      }
+  }
+
   if (current_buffer->text->intervals)
     (eassert (EQ (current_buffer->text->intervals->up.obj, buffer)),
      XSETBUFFER (current_buffer->text->intervals->up.obj, current_buffer));