Subject: Re: 24.2.93; Segmentation fault when trying to [s]teal a file opened elsewhere

From: Eli Zaretskii <[email-masked]>
Date: Sat, 23 Feb 2013 17:10:47 +0200

> Date: Sat, 23 Feb 2013 07:37:09 +0400
> From: Dmitry Gutov <[email-masked]>
> CC: [email-masked], Eli Zaretskii <[email-masked]>
> 
> > make clean
> > make CFLAGS='-g3 -DENABLE_CHECKING'
> 
> So, I compiled it with checking and it crashes with a failed assertion 
> in the same place. Not sure how useful that is.

It catches the problem one step before we segfault:

> #1  0x000000000069a6c2 in die (msg=0x8c9ac4 "assertion failed: i != 0",
>      file=0x8c8fa8 "textprop.c", line=1173) at alloc.c:6440
> No locals.
> #2  0x0000000000768f5b in Fadd_text_properties (start=4, end=3068,
>      properties=30489510, object=30971749) at textprop.c:1173
>          i = 0x0
>          unchanged = 0x7fffffffc130
>          s = 1
>          len = 558
>          modified = 19
>          gcpro1 = {
>            next = 0xcac4d5 <pure+1643381>,
>            var = 0xcac461 <pure+1643265>,
>            nvars = 579820584989
>          }

This is where it aborts:

  if (BUFFERP (object))
    modify_region (XBUFFER (object), XINT (start), XINT (end), 1);

  /* We are at the beginning of interval I, with LEN chars to scan.  */
  for (;;)
    {
      eassert (i != 0);  <<<<<<<<<<<<<<<<<<<<<<<<<

      if (LENGTH (i) >= len)

Anyway, this problem happens because add-text-properties is re-entered
from the call to modify_region shown above.  That function calls
prepare_to_modify_buffer, which calls lock_file, which calls
ask-user-about-lock, which enters redisplay, which tries to fontify
the current buffer, which calls add-text-properties again.  This
recursive call modifies the interval tree for the current buffer, so
when modify_region returns, the interval whose pointer 'i' we computed
before calling modify_region is no longer correct (the interval
structure to which 'i' points has changed), and the rest is history.

I attach below the backtrace that clearly shows the recursive
invocation of add-text-properties.

I can fix this particular problem with this simple patch:

=== modified file 'src/textprop.c'
--- src/textprop.c	2013-01-02 16:13:04 +0000
+++ src/textprop.c	2013-02-23 14:56:45 +0000
@@ -1175,7 +1175,24 @@ Return t if any property value actually 
     }
 
   if (BUFFERP (object))
-    modify_region (object, start, end);
+    {
+      ptrdiff_t prev_total_length = i->total_length;
+      ptrdiff_t prev_pos = i->position;
+
+      modify_region (object, start, end);
+      /* If someone called us, as a side effect of modify_region, and
+	 changed the intervals behind our back (could happen if
+	 lock_file, called by prepare_to_modify_buffer, triggers
+	 redisplay and that calls add-text-properties again in the
+	 same buffer), we cannot continue with I.  So re-invoke
+	 ourselves, to have the intervals evaluated anew.  */
+      if (i->total_length != prev_total_length
+	  || i->position != prev_pos)
+        {
+	  UNGCPRO;
+	  return Fadd_text_properties (start, end, properties, object);
+        }
+    }
 
   /* We are at the beginning of interval I, with LEN chars to scan.  */
   for (;;)

However, I'm not sure this is the right or the best way.  If it is, it
will probably be prudent to add some protection against infinite
recursion here.

Here's the backtrace from the recursive call to add-text-properties.
It ends at rotate_right because I caught this by setting a watchpoint
at i->total_length, and the watchpoint fired when that was changed.

#0  rotate_right (interval=0x1693738) at intervals.c:374
#1  0x0000000000732aa5 in balance_an_interval (i=0x1693738) at intervals.c:448
#2  0x0000000000732c27 in balance_possible_root_interval (interval=0x1693738)
    at intervals.c:484
#3  0x000000000073311f in split_interval_left (interval=0x1693738, offset=506)
    at intervals.c:617
#4  0x000000000073d713 in Fadd_text_properties (start=4, end=2028,
    properties=22501590, object=23493237) at textprop.c:1212
#5  0x000000000073d89b in Fput_text_property (start=4, end=2028,
    property=15624258, value=15399602, object=15399554) at textprop.c:1239
#6  0x000000000069c49b in Ffuncall (nargs=5, args=0x7fffffff02c8)
    at eval.c:2691
#7  0x000000000070bdfd in exec_byte_code (bytestr=12996377, vector=12996685,
    maxdepth=32, args_template=15399554, nargs=0, args=0x0) at bytecode.c:898
#8  0x000000000069d353 in funcall_lambda (fun=12996333, nargs=2,
    arg_vector=0xc6504d <pure+1601741>) at eval.c:2907
#9  0x000000000069c6e9 in Ffuncall (nargs=3, args=0x7fffffff07c8)
    at eval.c:2724
#10 0x000000000070bdfd in exec_byte_code (bytestr=12995609, vector=12995837,
    maxdepth=40, args_template=15399554, nargs=0, args=0x0) at bytecode.c:898
#11 0x000000000069d353 in funcall_lambda (fun=12995565, nargs=1,
    arg_vector=0xc64cfd <pure+1600893>) at eval.c:2907
#12 0x000000000069c6e9 in Ffuncall (nargs=2, args=0x7fffffff0e70)
    at eval.c:2724
#13 0x0000000000697a3c in internal_condition_case_n (bfun=0x69ba9e <Ffuncall>,
    nargs=2, args=0x7fffffff0e70, handlers=15399602,
    hfun=0x44709f <safe_eval_handler>) at eval.c:1317
#14 0x00000000004472f7 in safe_call (nargs=2, func=23095458) at xdisp.c:2432
#15 0x0000000000447368 in safe_call1 (fn=23095458, arg=4) at xdisp.c:2448
#16 0x000000000044b318 in handle_fontified_prop (it=0x7fffffff11f0)
    at xdisp.c:3667
#17 0x000000000044a17a in handle_stop (it=0x7fffffff11f0) at xdisp.c:3231
#18 0x00000000004556f9 in reseat (it=0x7fffffff11f0, pos=..., force_p=1)
    at xdisp.c:6271
#19 0x0000000000448fee in init_iterator (it=0x7fffffff11f0, w=0xec3598,
    charpos=1, bytepos=1, row=0x1643140, base_face_id=DEFAULT_FACE_ID)
    at xdisp.c:2888
#20 0x0000000000449268 in start_display (it=0x7fffffff11f0, w=0xec3598,
    pos=...) at xdisp.c:2904
#21 0x000000000047b80f in try_window (window=15480221, pos=..., flags=1)
    at xdisp.c:16096
#22 0x0000000000478b55 in redisplay_window (window=15480221, just_this_one_p=0)
    at xdisp.c:15631
#23 0x0000000000470a0b in redisplay_window_0 (window=15480221) at xdisp.c:13685
#24 0x0000000000697736 in internal_condition_case_1 (
    bfun=0x4709c9 <redisplay_window_0>, arg=15480221, handlers=15370182,
    hfun=0x470998 <redisplay_window_error>) at eval.c:1231
#25 0x0000000000470979 in redisplay_windows (window=15480221) at xdisp.c:13665
#26 0x000000000046ee3c in redisplay_internal () at xdisp.c:13271
#27 0x0000000000465f90 in echo_area_display (update_frame_p=1) at xdisp.c:10685
#28 0x0000000000461f7f in message3_nolog (m=16562561) at xdisp.c:9650
#29 0x0000000000461ac9 in message3 (m=16562561) at xdisp.c:9596
#30 0x000000000068d088 in Fmessage (nargs=3, args=0x7fffffff5a10)
    at editfns.c:3462
#31 0x000000000069bf6b in Ffuncall (nargs=4, args=0x7fffffff5a08)
    at eval.c:2656
#32 0x000000000070bdfd in exec_byte_code (bytestr=16578913, vector=15479317,
    maxdepth=24, args_template=15399554, nargs=0, args=0x0) at bytecode.c:898
#33 0x000000000069d353 in funcall_lambda (fun=21727621, nargs=2,
    arg_vector=0xec3215) at eval.c:2907
#34 0x000000000069c6e9 in Ffuncall (nargs=3, args=0x7fffffff5f10)
    at eval.c:2724
#35 0x000000000069b815 in call2 (fn=19454322, arg1=16142209, arg2=16597585)
    at eval.c:2484
#36 0x000000000060db60 in lock_file (fn=16142209) at filelock.c:590
#37 0x0000000000613f76 in prepare_to_modify_buffer (start=1, end=515,
    preserve_ptr=0x0) at insdel.c:1829
#38 0x0000000000613a22 in modify_region_1 (start=1, end=515,
    preserve_chars_modiff=true) at insdel.c:1763
#39 0x00000000007389f8 in modify_region (buffer=16202757, start=4, end=2060)
    at textprop.c:97
#40 0x000000000073d4ee in Fadd_text_properties (start=4, end=2060,
    properties=22458134, object=16202757) at textprop.c:1178

Lisp Backtrace:
"put-text-property" (0xffff02d0)
"jit-lock-fontify-now" (0xffff07d0)
"jit-lock-function" (0xffff0e78)
"redisplay_internal (C function)" (0xea33d8)
"message" (0xffff5a10)
"ask-user-about-lock" (0xffff5f18)
"put-text-property" (0xffff6370)
"jit-lock-refontify" (0xffff6860)
"jit-lock-mode" (0xffff6d70)
"jit-lock-register" (0xffff7250)
"font-lock-turn-on-thing-lock" (0xffff7740)
"font-lock-mode-internal" (0xffff7c20)
"font-lock-default-function" (0xffff8100)
"font-lock-mode" (0xffff85e0)
"turn-on-font-lock" (0xffff8aa0)
"turn-on-font-lock-if-desired" (0xffff8f70)
"global-font-lock-mode-enable-in-buffers" (0xffff9528)
"run-hooks" (0xffff95f8)
"apply" (0xffff9780)
"run-mode-hooks" (0xffff9ba0)
"html-erb-mode" (0xffff9fa8)
"funcall" (0xffff9fa0)
"save-current-buffer" (0xffffa310)
"unwind-protect" (0xffffa4e0)
"let" (0xffffa7c0)
"if" (0xffffaa00)
"let" (0xffffad00)
"mmm-update-mode-info" (0xffffae20)
"if" (0xffffb280)
"if" (0xffffb4c0)
"mmm-mode-on" (0xffffb5e0)
"cond" (0xffffba30)
"mmm-mode-on-maybe" (0xffffbc18)
"funcall" (0xffffbc10)
"progn" (0xffffbf50)
"condition-case" (0xffffc2c0)
"while" (0xffffc520)
"let" (0xffffc800)
"progn" (0xffffc9f0)
"mmm-run-major-mode-hook" (0xffffcb10)
"save-current-buffer" (0xffffcf40)
"progn" (0xffffd130)
"if" (0xffffd320)
"while" (0xffffd580)
"let" (0xffffd860)
"progn" (0xffffda50)
"mmm-check-changed-buffers" (0xffffdc30)