diff options
| author | Eli Zaretskii | 2014-12-10 19:39:37 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2014-12-10 19:42:12 +0200 |
| commit | f3e16cbb5258fcbe2969eb48b332b2c629cfb2a6 (patch) | |
| tree | b92dd39f0b8a18caa28da17b09ec62740d2dca1f /src | |
| parent | 8bc7ac5c25f42b745cc90131a9a456f763582dbf (diff) | |
| download | emacs-f3e16cbb5258fcbe2969eb48b332b2c629cfb2a6.tar.gz emacs-f3e16cbb5258fcbe2969eb48b332b2c629cfb2a6.zip | |
Fix out-of-memory condition in display of long bracketed lines (bug#19322)
src/bidi.c (BIDI_CACHE_MAX_ELTS_PER_SLOT): New macro.
(bidi_cache_max_elts): New global variable.
(bidi_shelve_header_size): Add the sizeof bidi_cache_max_elts.
(bidi_cache_shrink, bidi_initialize): Reset bidi_cache_max_elts to
its initial value.
(bidi_cache_search): Handle overflown cache. Improve commentary.
(bidi_cache_ensure_space): Limit allocations to the current value
of bidi_cache_max_elts. Force xpalloc not to over-allocate. If
less than a full BIDI_CACHE_CHUNK is left to the limit, decrease
the increment to not exceed the limit.
(bidi_cache_iterator_state): Now returns non-zero if succeeded to
cache, zero otherwise (meaning the cache overflowed). In the
latter case, set bidi_cache_last_idx to -1.
(bidi_peek_at_next_level): Handle overflown cache.
(bidi_push_it): Increase the cache limit for iterating the new
object.
(bidi_pop_it): Decrease the cache limit back to previous value.
(bidi_shelve_cache): Shelve the current value of the cache limit.
(bidi_unshelve_cache): Restore the value of cache limit.
(bidi_find_bracket_pairs): If the cache overflows while looking
for the paired bracket, give up and let bidi_resolve_neutrals
process the bracket as a simple neutral.
(bidi_find_other_level_edge): If the cache overflows, fall back on
Plan B, which effectively stops the reordering and restarts it on
the next character (after resetting the cache).
(bidi_move_to_visually_next): When the cache overflows, reset it
after processing the last cached character.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 30 | ||||
| -rw-r--r-- | src/bidi.c | 191 |
2 files changed, 190 insertions, 31 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 09268d1b6cd..2a6e2373fcd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,33 @@ | |||
| 1 | 2014-12-10 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * bidi.c (BIDI_CACHE_MAX_ELTS_PER_SLOT): New macro. | ||
| 4 | (bidi_cache_max_elts): New global variable. | ||
| 5 | (bidi_shelve_header_size): Add the sizeof bidi_cache_max_elts. | ||
| 6 | (bidi_cache_shrink, bidi_initialize): Reset bidi_cache_max_elts to | ||
| 7 | its initial value. | ||
| 8 | (bidi_cache_search): Handle overflown cache. Improve commentary. | ||
| 9 | (bidi_cache_ensure_space): Limit allocations to the current value | ||
| 10 | of bidi_cache_max_elts. Force xpalloc not to over-allocate. If | ||
| 11 | less than a full BIDI_CACHE_CHUNK is left to the limit, decrease | ||
| 12 | the increment to not exceed the limit. | ||
| 13 | (bidi_cache_iterator_state): Now returns non-zero if succeeded to | ||
| 14 | cache, zero otherwise (meaning the cache overflowed). In the | ||
| 15 | latter case, set bidi_cache_last_idx to -1. | ||
| 16 | (bidi_peek_at_next_level): Handle overflown cache. | ||
| 17 | (bidi_push_it): Increase the cache limit for iterating the new | ||
| 18 | object. | ||
| 19 | (bidi_pop_it): Decrease the cache limit back to previous value. | ||
| 20 | (bidi_shelve_cache): Shelve the current value of the cache limit. | ||
| 21 | (bidi_unshelve_cache): Restore the value of cache limit. | ||
| 22 | (bidi_find_bracket_pairs): If the cache overflows while looking | ||
| 23 | for the paired bracket, give up and let bidi_resolve_neutrals | ||
| 24 | process the bracket as a simple neutral. (Bug#19322) | ||
| 25 | (bidi_find_other_level_edge): If the cache overflows, fall back on | ||
| 26 | Plan B, which effectively stops the reordering and restarts it on | ||
| 27 | the next character (after resetting the cache). | ||
| 28 | (bidi_move_to_visually_next): When the cache overflows, reset it | ||
| 29 | after processing the last cached character. | ||
| 30 | |||
| 1 | 2014-12-10 Paul Eggert <eggert@cs.ucla.edu> | 31 | 2014-12-10 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 32 | ||
| 3 | Fix glitches in gnutls.c, mostly memory-related | 33 | Fix glitches in gnutls.c, mostly memory-related |
diff --git a/src/bidi.c b/src/bidi.c index cc70d08f01e..0d291fcb033 100644 --- a/src/bidi.c +++ b/src/bidi.c | |||
| @@ -546,6 +546,30 @@ bidi_copy_it (struct bidi_it *to, struct bidi_it *from) | |||
| 546 | characters). 200 was chosen as an upper limit for reasonably-long | 546 | characters). 200 was chosen as an upper limit for reasonably-long |
| 547 | lines in a text file/buffer. */ | 547 | lines in a text file/buffer. */ |
| 548 | #define BIDI_CACHE_CHUNK 200 | 548 | #define BIDI_CACHE_CHUNK 200 |
| 549 | /* Maximum size we allow the cache to become, per iterator stack slot, | ||
| 550 | in units of struct bidi_it size. If we allow unlimited growth, we | ||
| 551 | could run out of memory for pathologically long bracketed text or | ||
| 552 | very long text lines that need to be reordered. This is aggravated | ||
| 553 | when word-wrap is in effect, since then functions display_line and | ||
| 554 | move_it_in_display_line_to need to keep up to 4 copies of the | ||
| 555 | cache. | ||
| 556 | |||
| 557 | This limitation means there can be no more than that amount of | ||
| 558 | contiguous RTL text on any single physical line in a LTR paragraph, | ||
| 559 | and similarly with contiguous LTR + numeric text in a RTL | ||
| 560 | paragraph. (LTR text in a LTR paragraph and RTL text in a RTL | ||
| 561 | paragraph are not reordered, and so don't need the cache, and | ||
| 562 | cannot hit this limit.) More importantly, no single line can have | ||
| 563 | text longer than this inside paired brackets (because bracket pairs | ||
| 564 | resolution uses the cache). If the limit is exceeded, the fallback | ||
| 565 | code will produce visual order that will be incorrect if there are | ||
| 566 | RTL characters in the offending line of text. */ | ||
| 567 | /* Do we need to allow customization of this limit? */ | ||
| 568 | #define BIDI_CACHE_MAX_ELTS_PER_SLOT 50000 | ||
| 569 | #if BIDI_CACHE_CHUNK >= BIDI_CACHE_MAX_ELTS_PER_SLOT | ||
| 570 | # error BIDI_CACHE_CHUNK must be less than BIDI_CACHE_MAX_ELTS_PER_SLOT | ||
| 571 | #endif | ||
| 572 | static ptrdiff_t bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT; | ||
| 549 | static struct bidi_it *bidi_cache; | 573 | static struct bidi_it *bidi_cache; |
| 550 | static ptrdiff_t bidi_cache_size = 0; | 574 | static ptrdiff_t bidi_cache_size = 0; |
| 551 | enum { elsz = sizeof (struct bidi_it) }; | 575 | enum { elsz = sizeof (struct bidi_it) }; |
| @@ -566,7 +590,7 @@ enum | |||
| 566 | bidi_shelve_header_size | 590 | bidi_shelve_header_size |
| 567 | = (sizeof (bidi_cache_idx) + sizeof (bidi_cache_start_stack) | 591 | = (sizeof (bidi_cache_idx) + sizeof (bidi_cache_start_stack) |
| 568 | + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) | 592 | + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) |
| 569 | + sizeof (bidi_cache_last_idx)) | 593 | + sizeof (bidi_cache_last_idx) + sizeof (bidi_cache_max_elts)) |
| 570 | }; | 594 | }; |
| 571 | 595 | ||
| 572 | /* Effectively remove the cached states beyond the Nth state from the | 596 | /* Effectively remove the cached states beyond the Nth state from the |
| @@ -604,6 +628,7 @@ bidi_cache_shrink (void) | |||
| 604 | bidi_cache_size = BIDI_CACHE_CHUNK; | 628 | bidi_cache_size = BIDI_CACHE_CHUNK; |
| 605 | } | 629 | } |
| 606 | bidi_cache_reset (); | 630 | bidi_cache_reset (); |
| 631 | bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT; | ||
| 607 | } | 632 | } |
| 608 | 633 | ||
| 609 | static void | 634 | static void |
| @@ -622,7 +647,9 @@ bidi_cache_fetch_state (ptrdiff_t idx, struct bidi_it *bidi_it) | |||
| 622 | /* Find a cached state with a given CHARPOS and resolved embedding | 647 | /* Find a cached state with a given CHARPOS and resolved embedding |
| 623 | level less or equal to LEVEL. If LEVEL is -1, disregard the | 648 | level less or equal to LEVEL. If LEVEL is -1, disregard the |
| 624 | resolved levels in cached states. DIR, if non-zero, means search | 649 | resolved levels in cached states. DIR, if non-zero, means search |
| 625 | in that direction from the last cache hit. */ | 650 | in that direction from the last cache hit. |
| 651 | |||
| 652 | Value is the index of the cached state, or -1 if not found. */ | ||
| 626 | static ptrdiff_t | 653 | static ptrdiff_t |
| 627 | bidi_cache_search (ptrdiff_t charpos, int level, int dir) | 654 | bidi_cache_search (ptrdiff_t charpos, int level, int dir) |
| 628 | { | 655 | { |
| @@ -696,7 +723,8 @@ bidi_cache_find_level_change (int level, int dir, bool before) | |||
| 696 | ptrdiff_t i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1; | 723 | ptrdiff_t i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1; |
| 697 | int incr = before ? 1 : 0; | 724 | int incr = before ? 1 : 0; |
| 698 | 725 | ||
| 699 | eassert (!dir || bidi_cache_last_idx >= 0); | 726 | if (i < 0) /* cache overflowed? */ |
| 727 | i = 0; | ||
| 700 | 728 | ||
| 701 | if (!dir) | 729 | if (!dir) |
| 702 | dir = -1; | 730 | dir = -1; |
| @@ -734,23 +762,37 @@ bidi_cache_ensure_space (ptrdiff_t idx) | |||
| 734 | /* Enlarge the cache as needed. */ | 762 | /* Enlarge the cache as needed. */ |
| 735 | if (idx >= bidi_cache_size) | 763 | if (idx >= bidi_cache_size) |
| 736 | { | 764 | { |
| 737 | /* The bidi cache cannot be larger than the largest Lisp string | 765 | ptrdiff_t chunk_size = BIDI_CACHE_CHUNK; |
| 738 | or buffer. */ | ||
| 739 | ptrdiff_t string_or_buffer_bound | ||
| 740 | = max (BUF_BYTES_MAX, STRING_BYTES_BOUND); | ||
| 741 | 766 | ||
| 742 | /* Also, it cannot be larger than what C can represent. */ | 767 | if (bidi_cache_size > bidi_cache_max_elts - chunk_size) |
| 743 | ptrdiff_t c_bound | 768 | chunk_size = bidi_cache_max_elts - bidi_cache_size; |
| 744 | = (min (PTRDIFF_MAX, SIZE_MAX) - bidi_shelve_header_size) / elsz; | ||
| 745 | 769 | ||
| 746 | bidi_cache | 770 | if (max (idx + 1, |
| 747 | = xpalloc (bidi_cache, &bidi_cache_size, | 771 | bidi_cache_size + chunk_size) <= bidi_cache_max_elts) |
| 748 | max (BIDI_CACHE_CHUNK, idx - bidi_cache_size + 1), | 772 | { |
| 749 | min (string_or_buffer_bound, c_bound), elsz); | 773 | /* The bidi cache cannot be larger than the largest Lisp |
| 774 | string or buffer. */ | ||
| 775 | ptrdiff_t string_or_buffer_bound | ||
| 776 | = max (BUF_BYTES_MAX, STRING_BYTES_BOUND); | ||
| 777 | |||
| 778 | /* Also, it cannot be larger than what C can represent. */ | ||
| 779 | ptrdiff_t c_bound | ||
| 780 | = (min (PTRDIFF_MAX, SIZE_MAX) - bidi_shelve_header_size) / elsz; | ||
| 781 | ptrdiff_t max_elts = bidi_cache_max_elts; | ||
| 782 | |||
| 783 | max_elts = min (max_elts, min (string_or_buffer_bound, c_bound)); | ||
| 784 | |||
| 785 | /* Force xpalloc not to over-allocate by passing it MAX_ELTS | ||
| 786 | as its 4th argument. */ | ||
| 787 | bidi_cache = xpalloc (bidi_cache, &bidi_cache_size, | ||
| 788 | max (chunk_size, idx - bidi_cache_size + 1), | ||
| 789 | max_elts, elsz); | ||
| 790 | eassert (bidi_cache_size > idx); | ||
| 791 | } | ||
| 750 | } | 792 | } |
| 751 | } | 793 | } |
| 752 | 794 | ||
| 753 | static void | 795 | static int |
| 754 | bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved, | 796 | bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved, |
| 755 | bool update_only) | 797 | bool update_only) |
| 756 | { | 798 | { |
| @@ -762,7 +804,7 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved, | |||
| 762 | idx = bidi_cache_search (bidi_it->charpos, -1, 1); | 804 | idx = bidi_cache_search (bidi_it->charpos, -1, 1); |
| 763 | 805 | ||
| 764 | if (idx < 0 && update_only) | 806 | if (idx < 0 && update_only) |
| 765 | return; | 807 | return 0; |
| 766 | 808 | ||
| 767 | if (idx < 0) | 809 | if (idx < 0) |
| 768 | { | 810 | { |
| @@ -771,19 +813,23 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved, | |||
| 771 | /* Character positions should correspond to cache positions 1:1. | 813 | /* Character positions should correspond to cache positions 1:1. |
| 772 | If we are outside the range of cached positions, the cache is | 814 | If we are outside the range of cached positions, the cache is |
| 773 | useless and must be reset. */ | 815 | useless and must be reset. */ |
| 774 | if (idx > bidi_cache_start && | 816 | if (bidi_cache_start < idx && idx < bidi_cache_size |
| 775 | (bidi_it->charpos > (bidi_cache[idx - 1].charpos | 817 | && (bidi_it->charpos > (bidi_cache[idx - 1].charpos |
| 776 | + bidi_cache[idx - 1].nchars) | 818 | + bidi_cache[idx - 1].nchars) |
| 777 | || bidi_it->charpos < bidi_cache[bidi_cache_start].charpos)) | 819 | || bidi_it->charpos < bidi_cache[bidi_cache_start].charpos)) |
| 778 | { | 820 | { |
| 779 | bidi_cache_reset (); | 821 | bidi_cache_reset (); |
| 780 | idx = bidi_cache_start; | 822 | idx = bidi_cache_start; |
| 781 | } | 823 | } |
| 782 | if (bidi_it->nchars <= 0) | 824 | if (bidi_it->nchars <= 0) |
| 783 | emacs_abort (); | 825 | emacs_abort (); |
| 784 | bidi_copy_it (&bidi_cache[idx], bidi_it); | 826 | /* Don't cache if no available space in the cache. */ |
| 785 | if (!resolved) | 827 | if (bidi_cache_size > idx) |
| 786 | bidi_cache[idx].resolved_level = -1; | 828 | { |
| 829 | bidi_copy_it (&bidi_cache[idx], bidi_it); | ||
| 830 | if (!resolved) | ||
| 831 | bidi_cache[idx].resolved_level = -1; | ||
| 832 | } | ||
| 787 | } | 833 | } |
| 788 | else | 834 | else |
| 789 | { | 835 | { |
| @@ -806,9 +852,19 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved, | |||
| 806 | bidi_cache[idx].bracket_enclosed_type = bidi_it->bracket_enclosed_type; | 852 | bidi_cache[idx].bracket_enclosed_type = bidi_it->bracket_enclosed_type; |
| 807 | } | 853 | } |
| 808 | 854 | ||
| 809 | bidi_cache_last_idx = idx; | 855 | if (bidi_cache_size > idx) |
| 810 | if (idx >= bidi_cache_idx) | 856 | { |
| 811 | bidi_cache_idx = idx + 1; | 857 | bidi_cache_last_idx = idx; |
| 858 | if (idx >= bidi_cache_idx) | ||
| 859 | bidi_cache_idx = idx + 1; | ||
| 860 | return 1; | ||
| 861 | } | ||
| 862 | else | ||
| 863 | { | ||
| 864 | /* The cache overflowed. */ | ||
| 865 | bidi_cache_last_idx = -1; | ||
| 866 | return 0; | ||
| 867 | } | ||
| 812 | } | 868 | } |
| 813 | 869 | ||
| 814 | /* Look for a cached iterator state that corresponds to CHARPOS. If | 870 | /* Look for a cached iterator state that corresponds to CHARPOS. If |
| @@ -846,8 +902,13 @@ bidi_cache_find (ptrdiff_t charpos, bool resolved_only, struct bidi_it *bidi_it) | |||
| 846 | static int | 902 | static int |
| 847 | bidi_peek_at_next_level (struct bidi_it *bidi_it) | 903 | bidi_peek_at_next_level (struct bidi_it *bidi_it) |
| 848 | { | 904 | { |
| 849 | if (bidi_cache_idx == bidi_cache_start || bidi_cache_last_idx == -1) | 905 | if (bidi_cache_idx == bidi_cache_start) |
| 850 | emacs_abort (); | 906 | emacs_abort (); |
| 907 | /* If the cache overflowed, return the level of the last cached | ||
| 908 | character. */ | ||
| 909 | if (bidi_cache_last_idx == -1 | ||
| 910 | || (bidi_cache_last_idx >= bidi_cache_idx - 1 && bidi_it->scan_dir > 0)) | ||
| 911 | return bidi_cache[bidi_cache_idx - 1].resolved_level; | ||
| 851 | return bidi_cache[bidi_cache_last_idx + bidi_it->scan_dir].resolved_level; | 912 | return bidi_cache[bidi_cache_last_idx + bidi_it->scan_dir].resolved_level; |
| 852 | } | 913 | } |
| 853 | 914 | ||
| @@ -864,6 +925,8 @@ bidi_peek_at_next_level (struct bidi_it *bidi_it) | |||
| 864 | void | 925 | void |
| 865 | bidi_push_it (struct bidi_it *bidi_it) | 926 | bidi_push_it (struct bidi_it *bidi_it) |
| 866 | { | 927 | { |
| 928 | /* Give this stack slot its cache room. */ | ||
| 929 | bidi_cache_max_elts += BIDI_CACHE_MAX_ELTS_PER_SLOT; | ||
| 867 | /* Save the current iterator state in its entirety after the last | 930 | /* Save the current iterator state in its entirety after the last |
| 868 | used cache slot. */ | 931 | used cache slot. */ |
| 869 | bidi_cache_ensure_space (bidi_cache_idx); | 932 | bidi_cache_ensure_space (bidi_cache_idx); |
| @@ -900,6 +963,9 @@ bidi_pop_it (struct bidi_it *bidi_it) | |||
| 900 | 963 | ||
| 901 | /* Invalidate the last-used cache slot data. */ | 964 | /* Invalidate the last-used cache slot data. */ |
| 902 | bidi_cache_last_idx = -1; | 965 | bidi_cache_last_idx = -1; |
| 966 | |||
| 967 | bidi_cache_max_elts -= BIDI_CACHE_MAX_ELTS_PER_SLOT; | ||
| 968 | eassert (bidi_cache_max_elts > 0); | ||
| 903 | } | 969 | } |
| 904 | 970 | ||
| 905 | static ptrdiff_t bidi_cache_total_alloc; | 971 | static ptrdiff_t bidi_cache_total_alloc; |
| @@ -939,6 +1005,11 @@ bidi_shelve_cache (void) | |||
| 939 | + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) | 1005 | + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) |
| 940 | + sizeof (bidi_cache_start), | 1006 | + sizeof (bidi_cache_start), |
| 941 | &bidi_cache_last_idx, sizeof (bidi_cache_last_idx)); | 1007 | &bidi_cache_last_idx, sizeof (bidi_cache_last_idx)); |
| 1008 | memcpy (databuf + sizeof (bidi_cache_idx) | ||
| 1009 | + bidi_cache_idx * sizeof (struct bidi_it) | ||
| 1010 | + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) | ||
| 1011 | + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx), | ||
| 1012 | &bidi_cache_max_elts, sizeof (bidi_cache_max_elts)); | ||
| 942 | 1013 | ||
| 943 | return databuf; | 1014 | return databuf; |
| 944 | } | 1015 | } |
| @@ -960,6 +1031,7 @@ bidi_unshelve_cache (void *databuf, bool just_free) | |||
| 960 | /* A NULL pointer means an empty cache. */ | 1031 | /* A NULL pointer means an empty cache. */ |
| 961 | bidi_cache_start = 0; | 1032 | bidi_cache_start = 0; |
| 962 | bidi_cache_sp = 0; | 1033 | bidi_cache_sp = 0; |
| 1034 | bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT; | ||
| 963 | bidi_cache_reset (); | 1035 | bidi_cache_reset (); |
| 964 | } | 1036 | } |
| 965 | } | 1037 | } |
| @@ -999,6 +1071,12 @@ bidi_unshelve_cache (void *databuf, bool just_free) | |||
| 999 | + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) | 1071 | + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) |
| 1000 | + sizeof (bidi_cache_start), | 1072 | + sizeof (bidi_cache_start), |
| 1001 | sizeof (bidi_cache_last_idx)); | 1073 | sizeof (bidi_cache_last_idx)); |
| 1074 | memcpy (&bidi_cache_max_elts, | ||
| 1075 | p + sizeof (bidi_cache_idx) | ||
| 1076 | + bidi_cache_idx * sizeof (struct bidi_it) | ||
| 1077 | + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) | ||
| 1078 | + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx), | ||
| 1079 | sizeof (bidi_cache_max_elts)); | ||
| 1002 | bidi_cache_total_alloc | 1080 | bidi_cache_total_alloc |
| 1003 | -= (bidi_shelve_header_size | 1081 | -= (bidi_shelve_header_size |
| 1004 | + bidi_cache_idx * sizeof (struct bidi_it)); | 1082 | + bidi_cache_idx * sizeof (struct bidi_it)); |
| @@ -1045,6 +1123,7 @@ bidi_initialize (void) | |||
| 1045 | 1123 | ||
| 1046 | bidi_cache_sp = 0; | 1124 | bidi_cache_sp = 0; |
| 1047 | bidi_cache_total_alloc = 0; | 1125 | bidi_cache_total_alloc = 0; |
| 1126 | bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT; | ||
| 1048 | 1127 | ||
| 1049 | bidi_initialized = 1; | 1128 | bidi_initialized = 1; |
| 1050 | } | 1129 | } |
| @@ -2459,6 +2538,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it) | |||
| 2459 | struct bidi_it tem_it; | 2538 | struct bidi_it tem_it; |
| 2460 | bool l2r_seen = false, r2l_seen = false; | 2539 | bool l2r_seen = false, r2l_seen = false; |
| 2461 | ptrdiff_t pairing_pos; | 2540 | ptrdiff_t pairing_pos; |
| 2541 | int idx_at_entry = bidi_cache_idx; | ||
| 2462 | 2542 | ||
| 2463 | eassert (MAX_BPA_STACK >= 100); | 2543 | eassert (MAX_BPA_STACK >= 100); |
| 2464 | bidi_copy_it (&saved_it, bidi_it); | 2544 | bidi_copy_it (&saved_it, bidi_it); |
| @@ -2483,7 +2563,15 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it) | |||
| 2483 | levels below). */ | 2563 | levels below). */ |
| 2484 | if (btype == BIDI_BRACKET_OPEN && bidi_it->bracket_pairing_pos == -1) | 2564 | if (btype == BIDI_BRACKET_OPEN && bidi_it->bracket_pairing_pos == -1) |
| 2485 | bidi_it->bracket_pairing_pos = bidi_it->charpos; | 2565 | bidi_it->bracket_pairing_pos = bidi_it->charpos; |
| 2486 | bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0); | 2566 | if (!bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0)) |
| 2567 | { | ||
| 2568 | /* No more space in cache -- give up and let the opening | ||
| 2569 | bracket that started this be processed as a | ||
| 2570 | NEUTRAL_ON. */ | ||
| 2571 | bidi_cache_reset_to (idx_at_entry - bidi_cache_start); | ||
| 2572 | bidi_copy_it (bidi_it, &saved_it); | ||
| 2573 | goto give_up; | ||
| 2574 | } | ||
| 2487 | if (btype == BIDI_BRACKET_OPEN) | 2575 | if (btype == BIDI_BRACKET_OPEN) |
| 2488 | PUSH_BPA_STACK; | 2576 | PUSH_BPA_STACK; |
| 2489 | else if (btype == BIDI_BRACKET_CLOSE) | 2577 | else if (btype == BIDI_BRACKET_CLOSE) |
| @@ -2572,7 +2660,16 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it) | |||
| 2572 | { | 2660 | { |
| 2573 | if (maxlevel < bidi_it->level_stack[bidi_it->stack_idx].level) | 2661 | if (maxlevel < bidi_it->level_stack[bidi_it->stack_idx].level) |
| 2574 | maxlevel = bidi_it->level_stack[bidi_it->stack_idx].level; | 2662 | maxlevel = bidi_it->level_stack[bidi_it->stack_idx].level; |
| 2575 | bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0); | 2663 | if (!bidi_cache_iterator_state (bidi_it, |
| 2664 | type == NEUTRAL_B, 0)) | ||
| 2665 | { | ||
| 2666 | /* No more space in cache -- give up and let the | ||
| 2667 | opening bracket that started this be | ||
| 2668 | processed as any other NEUTRAL_ON. */ | ||
| 2669 | bidi_cache_reset_to (idx_at_entry - bidi_cache_start); | ||
| 2670 | bidi_copy_it (bidi_it, &saved_it); | ||
| 2671 | goto give_up; | ||
| 2672 | } | ||
| 2576 | type = bidi_resolve_weak (bidi_it); | 2673 | type = bidi_resolve_weak (bidi_it); |
| 2577 | } | 2674 | } |
| 2578 | } | 2675 | } |
| @@ -2648,6 +2745,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it) | |||
| 2648 | } | 2745 | } |
| 2649 | } | 2746 | } |
| 2650 | 2747 | ||
| 2748 | give_up: | ||
| 2651 | return retval; | 2749 | return retval; |
| 2652 | } | 2750 | } |
| 2653 | 2751 | ||
| @@ -3210,10 +3308,35 @@ bidi_find_other_level_edge (struct bidi_it *bidi_it, int level, bool end_flag) | |||
| 3210 | if (end_flag) | 3308 | if (end_flag) |
| 3211 | emacs_abort (); | 3309 | emacs_abort (); |
| 3212 | 3310 | ||
| 3213 | bidi_cache_iterator_state (bidi_it, 1, 0); | 3311 | if (!bidi_cache_iterator_state (bidi_it, 1, 0)) |
| 3312 | { | ||
| 3313 | /* Can't happen: if the cache needs to grow, it means we | ||
| 3314 | were at base embedding level, so the cache should have | ||
| 3315 | been either empty or already large enough to cover this | ||
| 3316 | character position. */ | ||
| 3317 | emacs_abort (); | ||
| 3318 | } | ||
| 3214 | do { | 3319 | do { |
| 3215 | new_level = bidi_level_of_next_char (bidi_it); | 3320 | new_level = bidi_level_of_next_char (bidi_it); |
| 3216 | bidi_cache_iterator_state (bidi_it, 1, 0); | 3321 | /* If the cache is full, perform an emergency return by |
| 3322 | pretending that the level ended. */ | ||
| 3323 | if (!bidi_cache_iterator_state (bidi_it, 1, 0)) | ||
| 3324 | { | ||
| 3325 | new_level = level - 1; | ||
| 3326 | /* Since the cache should only grow when we are scanning | ||
| 3327 | forward looking for the edge of the level that is one | ||
| 3328 | above the base embedding level, we can only have this | ||
| 3329 | contingency when LEVEL - 1 is the base embedding | ||
| 3330 | level. */ | ||
| 3331 | eassert (new_level == bidi_it->level_stack[0].level); | ||
| 3332 | /* Plan B, for when the cache overflows: Back up to the | ||
| 3333 | previous character by fetching the last cached state, | ||
| 3334 | and force the resolved level of that character be the | ||
| 3335 | base embedding level. */ | ||
| 3336 | bidi_cache_fetch_state (bidi_cache_idx - 1, bidi_it); | ||
| 3337 | bidi_it->resolved_level = new_level; | ||
| 3338 | bidi_cache_iterator_state (bidi_it, 1, 1); | ||
| 3339 | } | ||
| 3217 | } while (new_level >= level); | 3340 | } while (new_level >= level); |
| 3218 | } | 3341 | } |
| 3219 | } | 3342 | } |
| @@ -3367,6 +3490,12 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it) | |||
| 3367 | && bidi_it->charpos > (bidi_cache[bidi_cache_idx - 1].charpos | 3490 | && bidi_it->charpos > (bidi_cache[bidi_cache_idx - 1].charpos |
| 3368 | + bidi_cache[bidi_cache_idx - 1].nchars - 1)) | 3491 | + bidi_cache[bidi_cache_idx - 1].nchars - 1)) |
| 3369 | bidi_cache_reset (); | 3492 | bidi_cache_reset (); |
| 3493 | /* Also reset the cache if it overflowed and we have just | ||
| 3494 | emergency-exited using Plan B. */ | ||
| 3495 | else if (bidi_it->resolved_level == bidi_it->level_stack[0].level | ||
| 3496 | && bidi_cache_idx >= bidi_cache_size | ||
| 3497 | && bidi_it->charpos == bidi_cache[bidi_cache_idx - 1].charpos) | ||
| 3498 | bidi_cache_reset (); | ||
| 3370 | /* But as long as we are caching during forward scan, we must | 3499 | /* But as long as we are caching during forward scan, we must |
| 3371 | cache each state, or else the cache integrity will be | 3500 | cache each state, or else the cache integrity will be |
| 3372 | compromised: it assumes cached states correspond to buffer | 3501 | compromised: it assumes cached states correspond to buffer |