diff options
author | Eli Zaretskii <eliz@gnu.org> | 2013-03-02 11:28:53 +0200 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2013-03-02 11:28:53 +0200 |
commit | 18f2ac090d74eb0e91d5b3b8a6db01063264f254 (patch) | |
tree | 0dd3fd6edf7382f5fcc58e660c85c0d7d9116b65 /src/textprop.c | |
parent | c856b8d4679fe4b75f925c9e87eacf9456398090 (diff) | |
download | emacs-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.c | 46 |
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 (;;) |