]> git.eshelyaron.com Git - emacs.git/commitdiff
Protect against changes of interval tree when adding/removing text props.
authorEli Zaretskii <eliz@gnu.org>
Sat, 2 Mar 2013 09:28:53 +0000 (11:28 +0200)
committerEli Zaretskii <eliz@gnu.org>
Sat, 2 Mar 2013 09:28:53 +0000 (11:28 +0200)
 src/textprop.c (Fadd_text_properties, Fremove_text_properties): If
 the interval tree changes as a side effect of calling
 modify_region, re-do processing starting from the call to
 validate_interval_range.  (Bug#13743)

src/ChangeLog
src/textprop.c

index 1b8b3c560048b2fc2dc17e95767e9994b86a9b79..35cbab8409607d882aa2deced4bf1a4fcf2323df 100644 (file)
@@ -1,3 +1,10 @@
+2013-03-02  Eli Zaretskii  <eliz@gnu.org>
+
+       * textprop.c (Fadd_text_properties, Fremove_text_properties): If
+       the interval tree changes as a side effect of calling
+       modify_region, re-do processing starting from the call to
+       validate_interval_range.  (Bug#13743)
+
 2013-02-28  Eli Zaretskii  <eliz@gnu.org>
 
        * w32.c (sys_open): Don't reset the flags for FD in fd_info[].
index 9499b53301f3df08a802ef7a11138bb44bbedcde..34009131c096fe77c91e4637f7f8774722dbb385 100644 (file)
@@ -1131,6 +1131,7 @@ Return t if any property value actually changed, nil otherwise.  */)
   ptrdiff_t s, len;
   bool modified = 0;
   struct gcpro gcpro1;
+  int first_time = 1;
 
   properties = validate_plist (properties);
   if (NILP (properties))
@@ -1139,6 +1140,7 @@ Return t if any property value actually changed, nil otherwise.  */)
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
+ retry:
   i = validate_interval_range (object, &start, &end, hard);
   if (!i)
     return Qnil;
@@ -1174,8 +1176,25 @@ Return t if any property value actually changed, nil otherwise.  */)
       copy_properties (unchanged, i);
     }
 
-  if (BUFFERP (object))
-    modify_region (object, start, end);
+  if (BUFFERP (object) && first_time)
+    {
+      ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
+      ptrdiff_t prev_pos = i->position;
+
+      modify_region (object, start, end);
+      /* If someone called us recursively 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, because its
+        data changed.  So we restart the interval analysis anew.  */
+      if (TOTAL_LENGTH (i) != prev_total_length
+         || i->position != prev_pos)
+       {
+         first_time = 0;
+         goto retry;
+       }
+    }
 
   /* We are at the beginning of interval I, with LEN chars to scan.  */
   for (;;)
@@ -1427,10 +1446,12 @@ Use `set-text-properties' if you want to remove all text properties.  */)
   INTERVAL i, unchanged;
   ptrdiff_t s, len;
   bool modified = 0;
+  int first_time = 1;
 
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
+ retry:
   i = validate_interval_range (object, &start, &end, soft);
   if (!i)
     return Qnil;
@@ -1462,8 +1483,25 @@ Use `set-text-properties' if you want to remove all text properties.  */)
       copy_properties (unchanged, i);
     }
 
-  if (BUFFERP (object))
-    modify_region (object, start, end);
+  if (BUFFERP (object) && first_time)
+    {
+      ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
+      ptrdiff_t prev_pos = i->position;
+
+      modify_region (object, start, end);
+      /* If someone called us recursively 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, because its
+        data changed.  So we restart the interval analysis anew.  */
+      if (TOTAL_LENGTH (i) != prev_total_length
+         || i->position != prev_pos)
+       {
+         first_time = 0;
+         goto retry;
+       }
+    }
 
   /* We are at the beginning of an interval, with len to scan */
   for (;;)