The patch sent out by Hrvoje Niksic fixed the problem for me. I've
copied his message below.
On Thu, 5 Apr 2001, Ben Wing wrote:
 i would be grateful if you could trace the code and find the problem.
 the
 extent's endpoints should be getting changed in either adjust_extents[] or
 process_extents_for_insertion_mapper[].  [the latter function actually has a
 comment about zero-length closed-open extents: 
------------------------------------------------------------------------
Michael Toomim <toomim(a)OCF.Berkeley.EDU> writes:
 According to the info xemacs lisp reference and comments in
 extents.c, insertion at a zero-length extent with the properties
 start-open and end-closed (like the extent (5, 5]) should go before
 the extent: 
[...]
 Thus, for the above extent, if one inserts the text "###"
at
 position 5 in the buffer, the documentation implies that the extent
 would change to (8, 8].  This doesn't happen. With xemacs version
 21.1, patches 12 and 9, the extent instead expands to include the
 inserted text (like the extent [5, 5] does) -- causing the extent to
 change to (5, 8]. 
I think there is a logic flaw in process_extents_for_insertion_mapper.
The second test, which is supposed to handle zero-length open-open
extents, fails to correctly handle open-closed zero-length extents.
I believe the patch appended below should fix things.  It clearly
separates the legal cases that handle start-open and end-closed
correction from the aberrant open-open case.
Extents really call for an automated test.  I think I'll write one.
Ben, you wrote the extent code; does this patch look good to you?
--- src/extents.c.orig	Wed Apr  4 19:18:56 2001
+++ src/extents.c	Wed Apr  4 19:23:10 2001
@@ -4589,12 +4589,19 @@
     new_start = extent_start (extent);
     new_end = extent_end (extent);
-    if (indice == extent_start (extent) && extent_start_open_p (extent)
&&
-	/* coerce zero-length () extents to [) */
-	new_start != new_end)
+    if (indice == extent_start (extent) && extent_start_open_p (extent))
       new_start += closure->length;
     if (indice == extent_end (extent) && !extent_end_open_p (extent))
       new_end += closure->length;
+
+    if (new_start > new_end)
+      {
+	/* coerce zero-length () extents to [) */
+#ifdef ERROR_CHECK_EXTENTS
+	assert (extent_start_open_p (extent) && extent_end_open_p (extent));
+#endif
+	new_start = new_end;
+      }
     set_extent_endpoints_1 (extent, new_start, new_end);
   }