I nailed it!
Hrvoje Niksic <hniksic(a)iskon.hr> writes:
> #7 0x8122e65 in signal_after_change (buf=0x857e6b8, start=0,
orig_end=1,
> new_end=0) at /scratch/vroonhof/xemacs/src/insdel.c:2291
I don't understand how start ends up being 0, short of a memory
corruption.
The trace is actually correct!
It turns out that the buffer was deleted by lisp code during the
after_change_functions[1]. W3's fancy async stuff uses the a-c-f a lot
for nontrivial stuff. The whole page is rendered in an a-c-f!
The patch at end fixes the crash (but I still get a buffer-live-p lisp
error from somewhere).
I think that whole code should be audited for race conditions....
> P.S. Shouldn't bufcons and buffer be gcproed?
I don't think so. bufcons maps over the list of indirect children,
which is GC-safe.
... what happens when the buffer gets killed during the loop? Doesn't
that loose the head of the list?
etc etc..
Jan
Footnotes:
[1] Actually by another a-c-f running because an lisp event came in
that triggered insertions in another buffer.!
Index: insdel.c
===================================================================
RCS file: /usr/CVSroot/XEmacs/xemacs/src/insdel.c,v
retrieving revision 1.19.2.12
diff -u -u -r1.19.2.12 insdel.c
--- insdel.c 2000/02/19 09:24:54 1.19.2.12
+++ insdel.c 2000/03/18 00:36:16
@@ -2276,20 +2276,29 @@
}
}
- /* Make sure endpoints remain valid. after-change-functions
- might have modified the buffer. */
- if (start < BUF_BEGV (buf)) start = BUF_BEGV (buf);
- if (start > BUF_ZV (buf)) start = BUF_ZV (buf);
- if (new_end < BUF_BEGV (buf)) new_end = BUF_BEGV (buf);
- if (new_end > BUF_ZV (buf)) new_end = BUF_ZV (buf);
- if (orig_end < BUF_BEGV (buf)) orig_end = BUF_BEGV (buf);
- if (orig_end > BUF_ZV (buf)) orig_end = BUF_ZV (buf);
+ /* after-change-functions run lisp. Anything could have
+ happened (if not by a poor innocent a-c-f then by some
+ lisp triggered by an event) */
- MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons)
- {
- XSETBUFFER (buffer, mbuf);
- report_extent_modification (buffer, start, new_end, 1);
- }
+ /* buffer could have disappeared from under us ! */
+
+ if (BUFFER_LIVE_P(buf))
+ {
+ /* Make sure endpoints remain valid. after-change-functions
+ might have modified the buffer. */
+ if (start < BUF_BEGV (buf)) start = BUF_BEGV (buf);
+ if (start > BUF_ZV (buf)) start = BUF_ZV (buf);
+ if (new_end < BUF_BEGV (buf)) new_end = BUF_BEGV (buf);
+ if (new_end > BUF_ZV (buf)) new_end = BUF_ZV (buf);
+ if (orig_end < BUF_BEGV (buf)) orig_end = BUF_BEGV (buf);
+ if (orig_end > BUF_ZV (buf)) orig_end = BUF_ZV (buf);
+
+ MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons)
+ {
+ XSETBUFFER (buffer, mbuf);
+ report_extent_modification (buffer, start, new_end, 1);
+ }
+ }
unbind_to (speccount, Qnil); /* sets inside_change_hook back to 0 */
}
}