diff options
| author | Eli Zaretskii | 2013-02-25 18:13:42 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-02-25 18:13:42 +0200 |
| commit | 0248b0d70b891c952385daa787fb00c9bdd42935 (patch) | |
| tree | aafa490dd844b91e713981f8fcbd78b29a0a304f /src | |
| parent | b5071fc755c4f287c7befba1150d91a985762ebd (diff) | |
| download | emacs-0248b0d70b891c952385daa787fb00c9bdd42935.tar.gz emacs-0248b0d70b891c952385daa787fb00c9bdd42935.zip | |
Fix bug #13743 with crashes due to recursive add-text-properties.
src/textprop.c (Fadd_text_properties, Fremove_text_properties)
(Fremove_list_of_text_properties): Skip all of the intervals in
the region between START and END that already have resp. don't
have the requested properties, not just the first one. Add
assertions that the loop afterwards always modifies the
properties.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/textprop.c | 125 |
2 files changed, 75 insertions, 59 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 4f2fb4c1d53..dc9b97c3c03 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2013-02-25 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * textprop.c (Fadd_text_properties, Fremove_text_properties) | ||
| 4 | (Fremove_list_of_text_properties): Skip all of the intervals in | ||
| 5 | the region between START and END that already have resp. don't | ||
| 6 | have the requested properties, not just the first one. Add | ||
| 7 | assertions that the loop afterwards always modifies the | ||
| 8 | properties. (Bug#13743) | ||
| 9 | |||
| 1 | 2013-02-25 Stefan Monnier <monnier@iro.umontreal.ca> | 10 | 2013-02-25 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 11 | ||
| 3 | * callint.c (Fcall_interactively): Use the right lexical environment | 12 | * callint.c (Fcall_interactively): Use the right lexical environment |
diff --git a/src/textprop.c b/src/textprop.c index c1f6e59bf2e..49fe427913c 100644 --- a/src/textprop.c +++ b/src/textprop.c | |||
| @@ -1133,6 +1133,7 @@ Return t if any property value actually changed, nil otherwise. */) | |||
| 1133 | register ptrdiff_t s, len; | 1133 | register ptrdiff_t s, len; |
| 1134 | register int modified = 0; | 1134 | register int modified = 0; |
| 1135 | struct gcpro gcpro1; | 1135 | struct gcpro gcpro1; |
| 1136 | ptrdiff_t got; | ||
| 1136 | 1137 | ||
| 1137 | properties = validate_plist (properties); | 1138 | properties = validate_plist (properties); |
| 1138 | if (NILP (properties)) | 1139 | if (NILP (properties)) |
| @@ -1152,26 +1153,25 @@ Return t if any property value actually changed, nil otherwise. */) | |||
| 1152 | and live buffers are always protected. */ | 1153 | and live buffers are always protected. */ |
| 1153 | GCPRO1 (properties); | 1154 | GCPRO1 (properties); |
| 1154 | 1155 | ||
| 1155 | /* If we're not starting on an interval boundary, we have to | 1156 | /* If this interval already has the properties, we can skip it. */ |
| 1156 | split this interval. */ | 1157 | if (interval_has_all_properties (properties, i)) |
| 1157 | if (i->position != s) | ||
| 1158 | { | 1158 | { |
| 1159 | /* If this interval already has the properties, we can | 1159 | got = LENGTH (i) - (s - i->position); |
| 1160 | skip it. */ | 1160 | do { |
| 1161 | if (interval_has_all_properties (properties, i)) | 1161 | if (got >= len) |
| 1162 | { | 1162 | RETURN_UNGCPRO (Qnil); |
| 1163 | ptrdiff_t got = (LENGTH (i) - (s - i->position)); | 1163 | len -= got; |
| 1164 | if (got >= len) | 1164 | i = next_interval (i); |
| 1165 | RETURN_UNGCPRO (Qnil); | 1165 | got = LENGTH (i); |
| 1166 | len -= got; | 1166 | } while (interval_has_all_properties (properties, i)); |
| 1167 | i = next_interval (i); | 1167 | } |
| 1168 | } | 1168 | else if (i->position != s) |
| 1169 | else | 1169 | { |
| 1170 | { | 1170 | /* If we're not starting on an interval boundary, we have to |
| 1171 | unchanged = i; | 1171 | split this interval. */ |
| 1172 | i = split_interval_right (unchanged, s - unchanged->position); | 1172 | unchanged = i; |
| 1173 | copy_properties (unchanged, i); | 1173 | i = split_interval_right (unchanged, s - unchanged->position); |
| 1174 | } | 1174 | copy_properties (unchanged, i); |
| 1175 | } | 1175 | } |
| 1176 | 1176 | ||
| 1177 | if (BUFFERP (object)) | 1177 | if (BUFFERP (object)) |
| @@ -1195,7 +1195,8 @@ Return t if any property value actually changed, nil otherwise. */) | |||
| 1195 | signal_after_change (XINT (start), XINT (end) - XINT (start), | 1195 | signal_after_change (XINT (start), XINT (end) - XINT (start), |
| 1196 | XINT (end) - XINT (start)); | 1196 | XINT (end) - XINT (start)); |
| 1197 | 1197 | ||
| 1198 | return modified ? Qt : Qnil; | 1198 | eassert (modified); |
| 1199 | return Qt; | ||
| 1199 | } | 1200 | } |
| 1200 | 1201 | ||
| 1201 | if (LENGTH (i) == len) | 1202 | if (LENGTH (i) == len) |
| @@ -1426,6 +1427,7 @@ Use `set-text-properties' if you want to remove all text properties. */) | |||
| 1426 | register INTERVAL i, unchanged; | 1427 | register INTERVAL i, unchanged; |
| 1427 | register ptrdiff_t s, len; | 1428 | register ptrdiff_t s, len; |
| 1428 | register int modified = 0; | 1429 | register int modified = 0; |
| 1430 | ptrdiff_t got; | ||
| 1429 | 1431 | ||
| 1430 | if (NILP (object)) | 1432 | if (NILP (object)) |
| 1431 | XSETBUFFER (object, current_buffer); | 1433 | XSETBUFFER (object, current_buffer); |
| @@ -1437,26 +1439,25 @@ Use `set-text-properties' if you want to remove all text properties. */) | |||
| 1437 | s = XINT (start); | 1439 | s = XINT (start); |
| 1438 | len = XINT (end) - s; | 1440 | len = XINT (end) - s; |
| 1439 | 1441 | ||
| 1440 | if (i->position != s) | 1442 | /* If there are no properties on this entire interval, return. */ |
| 1443 | if (! interval_has_some_properties (properties, i)) | ||
| 1441 | { | 1444 | { |
| 1442 | /* No properties on this first interval -- return if | 1445 | got = (LENGTH (i) - (s - i->position)); |
| 1443 | it covers the entire region. */ | 1446 | do { |
| 1444 | if (! interval_has_some_properties (properties, i)) | 1447 | if (got >= len) |
| 1445 | { | 1448 | return Qnil; |
| 1446 | ptrdiff_t got = (LENGTH (i) - (s - i->position)); | 1449 | len -= got; |
| 1447 | if (got >= len) | 1450 | i = next_interval (i); |
| 1448 | return Qnil; | 1451 | got = LENGTH (i); |
| 1449 | len -= got; | 1452 | } while (! interval_has_some_properties (properties, i)); |
| 1450 | i = next_interval (i); | 1453 | } |
| 1451 | } | 1454 | /* Split away the beginning of this interval; what we don't |
| 1452 | /* Split away the beginning of this interval; what we don't | 1455 | want to modify. */ |
| 1453 | want to modify. */ | 1456 | else if (i->position != s) |
| 1454 | else | 1457 | { |
| 1455 | { | 1458 | unchanged = i; |
| 1456 | unchanged = i; | 1459 | i = split_interval_right (unchanged, s - unchanged->position); |
| 1457 | i = split_interval_right (unchanged, s - unchanged->position); | 1460 | copy_properties (unchanged, i); |
| 1458 | copy_properties (unchanged, i); | ||
| 1459 | } | ||
| 1460 | } | 1461 | } |
| 1461 | 1462 | ||
| 1462 | if (BUFFERP (object)) | 1463 | if (BUFFERP (object)) |
| @@ -1470,7 +1471,13 @@ Use `set-text-properties' if you want to remove all text properties. */) | |||
| 1470 | if (LENGTH (i) >= len) | 1471 | if (LENGTH (i) >= len) |
| 1471 | { | 1472 | { |
| 1472 | if (! interval_has_some_properties (properties, i)) | 1473 | if (! interval_has_some_properties (properties, i)) |
| 1473 | return modified ? Qt : Qnil; | 1474 | { |
| 1475 | eassert (modified); | ||
| 1476 | if (BUFFERP (object)) | ||
| 1477 | signal_after_change (XINT (start), XINT (end) - XINT (start), | ||
| 1478 | XINT (end) - XINT (start)); | ||
| 1479 | return Qt; | ||
| 1480 | } | ||
| 1474 | 1481 | ||
| 1475 | if (LENGTH (i) == len) | 1482 | if (LENGTH (i) == len) |
| 1476 | { | 1483 | { |
| @@ -1512,6 +1519,7 @@ Return t if any property was actually removed, nil otherwise. */) | |||
| 1512 | register ptrdiff_t s, len; | 1519 | register ptrdiff_t s, len; |
| 1513 | register int modified = 0; | 1520 | register int modified = 0; |
| 1514 | Lisp_Object properties; | 1521 | Lisp_Object properties; |
| 1522 | ptrdiff_t got; | ||
| 1515 | properties = list_of_properties; | 1523 | properties = list_of_properties; |
| 1516 | 1524 | ||
| 1517 | if (NILP (object)) | 1525 | if (NILP (object)) |
| @@ -1524,26 +1532,25 @@ Return t if any property was actually removed, nil otherwise. */) | |||
| 1524 | s = XINT (start); | 1532 | s = XINT (start); |
| 1525 | len = XINT (end) - s; | 1533 | len = XINT (end) - s; |
| 1526 | 1534 | ||
| 1527 | if (i->position != s) | 1535 | /* If there are no properties on the interval, return. */ |
| 1536 | if (! interval_has_some_properties_list (properties, i)) | ||
| 1528 | { | 1537 | { |
| 1529 | /* No properties on this first interval -- return if | 1538 | got = (LENGTH (i) - (s - i->position)); |
| 1530 | it covers the entire region. */ | 1539 | do { |
| 1531 | if (! interval_has_some_properties_list (properties, i)) | 1540 | if (got >= len) |
| 1532 | { | 1541 | return Qnil; |
| 1533 | ptrdiff_t got = (LENGTH (i) - (s - i->position)); | 1542 | len -= got; |
| 1534 | if (got >= len) | 1543 | i = next_interval (i); |
| 1535 | return Qnil; | 1544 | got = LENGTH (i); |
| 1536 | len -= got; | 1545 | } while (! interval_has_some_properties_list (properties, i)); |
| 1537 | i = next_interval (i); | 1546 | } |
| 1538 | } | 1547 | /* Split away the beginning of this interval; what we don't |
| 1539 | /* Split away the beginning of this interval; what we don't | 1548 | want to modify. */ |
| 1540 | want to modify. */ | 1549 | else if (i->position != s) |
| 1541 | else | 1550 | { |
| 1542 | { | 1551 | unchanged = i; |
| 1543 | unchanged = i; | 1552 | i = split_interval_right (unchanged, s - unchanged->position); |
| 1544 | i = split_interval_right (unchanged, s - unchanged->position); | 1553 | copy_properties (unchanged, i); |
| 1545 | copy_properties (unchanged, i); | ||
| 1546 | } | ||
| 1547 | } | 1554 | } |
| 1548 | 1555 | ||
| 1549 | /* We are at the beginning of an interval, with len to scan. | 1556 | /* We are at the beginning of an interval, with len to scan. |