summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2013-03-02 11:28:53 +0200
committerEli Zaretskii <eliz@gnu.org>2013-03-02 11:28:53 +0200
commit18f2ac090d74eb0e91d5b3b8a6db01063264f254 (patch)
tree0dd3fd6edf7382f5fcc58e660c85c0d7d9116b65
parentc856b8d4679fe4b75f925c9e87eacf9456398090 (diff)
downloademacs-18f2ac090d74eb0e91d5b3b8a6db01063264f254.tar.gz
Protect against changes of interval tree when adding/removing text props.
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)
-rw-r--r--src/ChangeLog7
-rw-r--r--src/textprop.c46
2 files changed, 49 insertions, 4 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 1b8b3c56004..35cbab84096 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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[].
diff --git a/src/textprop.c b/src/textprop.c
index 9499b53301f..34009131c09 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -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 (;;)