Skip to content

Commit 20fe5e4

Browse files
committed
Merge branch 'PHP-8.1'
* PHP-8.1: Fix IntlPartsIterator key off-by-one error
2 parents 04a4864 + e706d02 commit 20fe5e4

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

ext/intl/breakiterator/breakiterator_iterators.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ typedef struct zoi_break_iter_parts {
127127
zoi_with_current zoi_cur;
128128
parts_iter_key_type key_type;
129129
BreakIterator_object *bio; /* so we don't have to fetch it all the time */
130+
zend_ulong index_right;
130131
} zoi_break_iter_parts;
131132

132133
static void _breakiterator_parts_destroy_it(zend_object_iterator *iter)
@@ -136,8 +137,16 @@ static void _breakiterator_parts_destroy_it(zend_object_iterator *iter)
136137

137138
static void _breakiterator_parts_get_current_key(zend_object_iterator *iter, zval *key)
138139
{
139-
/* the actual work is done in move_forward and rewind */
140-
ZVAL_LONG(key, iter->index);
140+
// The engine resets the iterator index to -1 after rewinding. When using
141+
// PARTS_ITERATOR_KEY_RIGHT we store it in zoi_break_iter_parts.index_right
142+
// so it doesn't get lost.
143+
zoi_break_iter_parts *zoi_bit = (zoi_break_iter_parts*)iter;
144+
145+
if (zoi_bit->key_type == PARTS_ITERATOR_KEY_RIGHT && iter->index == 0) {
146+
ZVAL_LONG(key, zoi_bit->index_right);
147+
} else {
148+
ZVAL_LONG(key, iter->index);
149+
}
141150
}
142151

143152
static void _breakiterator_parts_move_forward(zend_object_iterator *iter)
@@ -163,6 +172,7 @@ static void _breakiterator_parts_move_forward(zend_object_iterator *iter)
163172
iter->index = cur;
164173
} else if (zoi_bit->key_type == PARTS_ITERATOR_KEY_RIGHT) {
165174
iter->index = next;
175+
zoi_bit->index_right = next;
166176
}
167177
/* else zoi_bit->key_type == PARTS_ITERATOR_KEY_SEQUENTIAL
168178
* No need to do anything, the engine increments ->index */
@@ -229,6 +239,7 @@ void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
229239
assert(((zoi_break_iter_parts*)ii->iterator)->bio->biter != NULL);
230240

231241
((zoi_break_iter_parts*)ii->iterator)->key_type = key_type;
242+
((zoi_break_iter_parts*)ii->iterator)->index_right = 0;
232243
}
233244

234245
U_CFUNC PHP_METHOD(IntlPartsIterator, getBreakIterator)

ext/intl/tests/gh7734.phpt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
GH-7734 (IntlPartsIterator key is wrong for KEY_LEFT/KEY_RIGHT)
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
8+
$iter = \IntlBreakIterator::createCodePointInstance();
9+
$iter->setText('ABC');
10+
11+
foreach ($iter->getPartsIterator(\IntlPartsIterator::KEY_SEQUENTIAL) as $key => $value) {
12+
var_dump($key, $value);
13+
}
14+
15+
foreach ($iter->getPartsIterator(\IntlPartsIterator::KEY_LEFT) as $key => $value) {
16+
var_dump($key, $value);
17+
}
18+
19+
foreach ($iter->getPartsIterator(\IntlPartsIterator::KEY_RIGHT) as $key => $value) {
20+
var_dump($key, $value);
21+
}
22+
23+
?>
24+
--EXPECT--
25+
int(0)
26+
string(1) "A"
27+
int(1)
28+
string(1) "B"
29+
int(2)
30+
string(1) "C"
31+
int(0)
32+
string(1) "A"
33+
int(1)
34+
string(1) "B"
35+
int(2)
36+
string(1) "C"
37+
int(1)
38+
string(1) "A"
39+
int(2)
40+
string(1) "B"
41+
int(3)
42+
string(1) "C"

0 commit comments

Comments
 (0)