summaryrefslogtreecommitdiff
path: root/src/textprop.c
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 /src/textprop.c
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)
Diffstat (limited to 'src/textprop.c')
-rw-r--r--src/textprop.c46
1 files changed, 42 insertions, 4 deletions
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 (;;)