mirror of
https://github.com/php/php-src.git
synced 2026-03-26 01:02:25 +01:00
Fix GH-15833: Segmentation fault (access null pointer) in ext/spl/spl_array.c
We're accessing the object properties table directly in spl, but we're not accounting for lazy objects. Upon accessing we should trigger the initialization as spl is doing direct manipulations on the object property table and expects a real object. Closes GH-17235.
This commit is contained in:
4
NEWS
4
NEWS
@@ -46,6 +46,10 @@ PHP NEWS
|
||||
. Fixed bug GH-17330 (SNMP::setSecurity segfault on closed session).
|
||||
(David Carlier)
|
||||
|
||||
- SPL:
|
||||
. Fixed bug GH-15833 (Segmentation fault (access null pointer) in
|
||||
ext/spl/spl_array.c). (nielsdos)
|
||||
|
||||
02 Jan 2025, PHP 8.4.3
|
||||
|
||||
- BcMath:
|
||||
|
||||
@@ -40,6 +40,7 @@ PHPAPI zend_class_entry *spl_ce_ArrayObject;
|
||||
|
||||
typedef struct _spl_array_object {
|
||||
zval array;
|
||||
HashTable *sentinel_array;
|
||||
uint32_t ht_iter;
|
||||
int ar_flags;
|
||||
unsigned char nApplyCount;
|
||||
@@ -74,6 +75,19 @@ static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern)
|
||||
return &Z_ARRVAL(intern->array);
|
||||
} else {
|
||||
zend_object *obj = Z_OBJ(intern->array);
|
||||
/* Since we're directly playing with the properties table, we shall initialize the lazy object directly.
|
||||
* If we don't, it's possible to continue working with the wrong object in case we're using a proxy. */
|
||||
if (UNEXPECTED(zend_lazy_object_must_init(obj))) {
|
||||
obj = zend_lazy_object_init(obj);
|
||||
if (UNEXPECTED(!obj)) {
|
||||
if (!intern->sentinel_array) {
|
||||
intern->sentinel_array = zend_new_array(0);
|
||||
}
|
||||
return &intern->sentinel_array;
|
||||
}
|
||||
}
|
||||
/* should no longer be lazy */
|
||||
ZEND_ASSERT(!zend_lazy_object_must_init(obj));
|
||||
/* rebuild properties */
|
||||
zend_std_get_properties_ex(obj);
|
||||
if (GC_REFCOUNT(obj->properties) > 1) {
|
||||
@@ -129,6 +143,10 @@ static void spl_array_object_free_storage(zend_object *object)
|
||||
zend_hash_iterator_del(intern->ht_iter);
|
||||
}
|
||||
|
||||
if (UNEXPECTED(intern->sentinel_array)) {
|
||||
zend_array_release(intern->sentinel_array);
|
||||
}
|
||||
|
||||
zend_object_std_dtor(&intern->std);
|
||||
|
||||
zval_ptr_dtor(&intern->array);
|
||||
@@ -489,6 +507,9 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
|
||||
uint32_t refcount = 0;
|
||||
if (!offset || Z_TYPE_P(offset) == IS_NULL) {
|
||||
ht = spl_array_get_hash_table(intern);
|
||||
if (UNEXPECTED(ht == intern->sentinel_array)) {
|
||||
return;
|
||||
}
|
||||
refcount = spl_array_set_refcount(intern->is_child, ht, 1);
|
||||
zend_hash_next_index_insert(ht, value);
|
||||
|
||||
@@ -505,6 +526,10 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
|
||||
}
|
||||
|
||||
ht = spl_array_get_hash_table(intern);
|
||||
if (UNEXPECTED(ht == intern->sentinel_array)) {
|
||||
spl_hash_key_release(&key);
|
||||
return;
|
||||
}
|
||||
refcount = spl_array_set_refcount(intern->is_child, ht, 1);
|
||||
if (key.key) {
|
||||
zend_hash_update_ind(ht, key.key, value);
|
||||
|
||||
22
ext/spl/tests/gh15833_1.phpt
Normal file
22
ext/spl/tests/gh15833_1.phpt
Normal file
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
GH-15833 (Segmentation fault (access null pointer) in ext/spl/spl_array.c)
|
||||
--CREDITS--
|
||||
YuanchengJiang
|
||||
--FILE--
|
||||
<?php
|
||||
class C {
|
||||
public int $a = 1;
|
||||
}
|
||||
$reflector = new ReflectionClass(C::class);
|
||||
$obj = $reflector->newLazyProxy(function ($obj) {
|
||||
$obj = new C();
|
||||
return $obj;
|
||||
});
|
||||
$recursiveArrayIterator = new RecursiveArrayIterator($obj);
|
||||
var_dump($recursiveArrayIterator->current());
|
||||
$recursiveArrayIterator->next();
|
||||
var_dump($recursiveArrayIterator->current());
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
NULL
|
||||
41
ext/spl/tests/gh15833_2.phpt
Normal file
41
ext/spl/tests/gh15833_2.phpt
Normal file
@@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
GH-15833 (Segmentation fault (access null pointer) in ext/spl/spl_array.c)
|
||||
--CREDITS--
|
||||
YuanchengJiang
|
||||
--FILE--
|
||||
<?php
|
||||
class C {
|
||||
public int $a = 1;
|
||||
}
|
||||
$reflector = new ReflectionClass(C::class);
|
||||
$obj = $reflector->newLazyProxy(function ($obj) {
|
||||
static $counter = 0;
|
||||
throw new Error('nope ' . ($counter++));
|
||||
});
|
||||
$recursiveArrayIterator = new RecursiveArrayIterator($obj);
|
||||
try {
|
||||
var_dump($recursiveArrayIterator->current());
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
var_dump($recursiveArrayIterator->current());
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
$recursiveArrayIterator->next();
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
var_dump($recursiveArrayIterator->current());
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
nope 0
|
||||
nope 1
|
||||
nope 2
|
||||
nope 3
|
||||
Reference in New Issue
Block a user