Skip to content

Commit 7cceda1

Browse files
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix GH-19577: avoid integer overflow when using a small offset and PHP_INT_MAX with LimitIterator (#19585)
2 parents ad129c6 + 05133ac commit 7cceda1

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

ext/spl/spl_iterators.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,14 +2124,27 @@ static zend_object *spl_dual_it_new(zend_class_entry *class_type)
21242124
}
21252125
/* }}} */
21262126

2127+
/* Returns the relative position for the current iterator position. */
2128+
static zend_long spl_limit_it_relative_pos(spl_dual_it_object *intern)
2129+
{
2130+
return intern->current.pos - intern->u.limit.offset;
2131+
}
2132+
2133+
/* Returns the relative position for an arbitrary position. */
2134+
static zend_long spl_limit_it_relative_pos_for(spl_dual_it_object *intern, zend_long pos)
2135+
{
2136+
return pos - intern->u.limit.offset;
2137+
}
2138+
21272139
static inline zend_result spl_limit_it_valid(spl_dual_it_object *intern)
21282140
{
21292141
/* FAILURE / SUCCESS */
2130-
if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
2142+
if (intern->u.limit.count != -1 &&
2143+
spl_limit_it_relative_pos(intern) >= intern->u.limit.count) {
21312144
return FAILURE;
2132-
} else {
2133-
return spl_dual_it_valid(intern);
21342145
}
2146+
2147+
return spl_dual_it_valid(intern);
21352148
}
21362149

21372150
static inline void spl_limit_it_seek(spl_dual_it_object *intern, zend_long pos)
@@ -2143,7 +2156,7 @@ static inline void spl_limit_it_seek(spl_dual_it_object *intern, zend_long pos)
21432156
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is below the offset " ZEND_LONG_FMT, pos, intern->u.limit.offset);
21442157
return;
21452158
}
2146-
if (pos - intern->u.limit.offset >= intern->u.limit.count && intern->u.limit.count != -1) {
2159+
if (spl_limit_it_relative_pos_for(intern, pos) >= intern->u.limit.count && intern->u.limit.count != -1) {
21472160
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is behind offset " ZEND_LONG_FMT " plus count " ZEND_LONG_FMT, pos, intern->u.limit.offset, intern->u.limit.count);
21482161
return;
21492162
}
@@ -2200,7 +2213,7 @@ PHP_METHOD(LimitIterator, valid)
22002213
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
22012214

22022215
/* RETURN_BOOL(spl_limit_it_valid(intern) == SUCCESS);*/
2203-
RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && Z_TYPE(intern->current.data) != IS_UNDEF);
2216+
RETURN_BOOL((intern->u.limit.count == -1 || spl_limit_it_relative_pos(intern) < intern->u.limit.count) && Z_TYPE(intern->current.data) != IS_UNDEF);
22042217
} /* }}} */
22052218

22062219
/* {{{ Move the iterator forward */
@@ -2213,7 +2226,7 @@ PHP_METHOD(LimitIterator, next)
22132226
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
22142227

22152228
spl_dual_it_next(intern, 1);
2216-
if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
2229+
if (intern->u.limit.count == -1 || spl_limit_it_relative_pos(intern) < intern->u.limit.count) {
22172230
spl_dual_it_fetch(intern, 1);
22182231
}
22192232
} /* }}} */

ext/spl/tests/gh19577.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-19577: Integer overflow in LimitIterator with small offset and PHP_INT_MAX count
3+
--FILE--
4+
<?php
5+
6+
$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'));
7+
$it = new LimitIterator($it, 2, PHP_INT_MAX);
8+
9+
foreach($it as $val => $key) {
10+
echo "Key: $val, Value: $key\n";
11+
}
12+
13+
?>
14+
--EXPECT--
15+
Key: 2, Value: C
16+
Key: 3, Value: D

0 commit comments

Comments
 (0)