From 18f2ac090d74eb0e91d5b3b8a6db01063264f254 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 2 Mar 2013 11:28:53 +0200 Subject: 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) --- src/textprop.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'src/textprop.c') 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 (;;) -- cgit v1.2.1