aboutsummaryrefslogtreecommitdiffstats
path: root/src/bidi.c
diff options
context:
space:
mode:
authorEli Zaretskii2014-12-10 19:39:37 +0200
committerEli Zaretskii2014-12-10 19:42:12 +0200
commitf3e16cbb5258fcbe2969eb48b332b2c629cfb2a6 (patch)
treeb92dd39f0b8a18caa28da17b09ec62740d2dca1f /src/bidi.c
parent8bc7ac5c25f42b745cc90131a9a456f763582dbf (diff)
downloademacs-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/bidi.c')
-rw-r--r--src/bidi.c191
1 files changed, 160 insertions, 31 deletions
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
572static ptrdiff_t bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT;
549static struct bidi_it *bidi_cache; 573static struct bidi_it *bidi_cache;
550static ptrdiff_t bidi_cache_size = 0; 574static ptrdiff_t bidi_cache_size = 0;
551enum { elsz = sizeof (struct bidi_it) }; 575enum { 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
609static void 634static 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. */
626static ptrdiff_t 653static ptrdiff_t
627bidi_cache_search (ptrdiff_t charpos, int level, int dir) 654bidi_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
753static void 795static int
754bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved, 796bidi_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)
846static int 902static int
847bidi_peek_at_next_level (struct bidi_it *bidi_it) 903bidi_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)
864void 925void
865bidi_push_it (struct bidi_it *bidi_it) 926bidi_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
905static ptrdiff_t bidi_cache_total_alloc; 971static 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