Skip to content

Commit fe2dc2b

Browse files
authored
Avoid crash for reset/end/next/prev() on ffi classes (#9711)
(And any PECLs returning `zend_empty_array` in the handler->get_properties overrides) Closes GH-9697 This is similar to the fix used in d9651a9 for array_walk. This should make it safer for php-src (and PECLs, long-term) to return the empty immutable array in `handler->get_properties` to avoid wasting memory. See #9697 (comment) The only possible internal iterator position for the empty array is at the end of the empty array (nInternalPointer=0). The `zend_hash*del*` helpers will always set nInternalPointer to 0 when an array becomes empty, regardless of previous insertions/deletions/updates to the array.
1 parent f7e6784 commit fe2dc2b

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ PHP NEWS
2727
. Fixed bug GH-10292 (Made the default value of the first param of srand() and
2828
mt_srand() unknown). (kocsismate)
2929
. Fix incorrect check in cs_8559_5 in map_from_unicode(). (nielsdos)
30+
. Fix bug GH-9697 for reset/end/next/prev() attempting to move pointer of
31+
properties table for certain internal classes such as FFI classes
3032

3133
02 Feb 2023, PHP 8.1.15
3234

ext/ffi/tests/arrayPointer.phpt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
FFI: Test deprecated use of array helper functions on FFI classes doesn't crash
3+
--EXTENSIONS--
4+
ffi
5+
--INI--
6+
ffi.enable=1
7+
--FILE--
8+
<?php
9+
error_reporting(E_ALL & ~E_DEPRECATED);
10+
$data = FFI::new('int');
11+
var_dump(reset($data));
12+
var_dump(end($data));
13+
var_dump(next($data));
14+
var_dump(prev($data));
15+
?>
16+
--EXPECTF--
17+
bool(false)
18+
bool(false)
19+
bool(false)
20+
bool(false)

ext/standard/array.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,10 @@ PHP_FUNCTION(end)
10731073
ZEND_PARSE_PARAMETERS_END();
10741074

10751075
HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1076+
if (zend_hash_num_elements(array) == 0) {
1077+
/* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1078+
RETURN_FALSE;
1079+
}
10761080
zend_hash_internal_pointer_end(array);
10771081

10781082
if (USED_RET()) {
@@ -1100,6 +1104,10 @@ PHP_FUNCTION(prev)
11001104
ZEND_PARSE_PARAMETERS_END();
11011105

11021106
HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1107+
if (zend_hash_num_elements(array) == 0) {
1108+
/* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1109+
RETURN_FALSE;
1110+
}
11031111
zend_hash_move_backwards(array);
11041112

11051113
if (USED_RET()) {
@@ -1127,6 +1135,10 @@ PHP_FUNCTION(next)
11271135
ZEND_PARSE_PARAMETERS_END();
11281136

11291137
HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1138+
if (zend_hash_num_elements(array) == 0) {
1139+
/* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1140+
RETURN_FALSE;
1141+
}
11301142
zend_hash_move_forward(array);
11311143

11321144
if (USED_RET()) {
@@ -1154,6 +1166,10 @@ PHP_FUNCTION(reset)
11541166
ZEND_PARSE_PARAMETERS_END();
11551167

11561168
HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1169+
if (zend_hash_num_elements(array) == 0) {
1170+
/* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1171+
RETURN_FALSE;
1172+
}
11571173
zend_hash_internal_pointer_reset(array);
11581174

11591175
if (USED_RET()) {

0 commit comments

Comments
 (0)