Closed
Description
Description
The following code:
<?php
$x = FFI::new('int');
array_walk($x, function($x) { echo "test\n"; });
Resulted in this output:
segmentation fault (core dumped)
valgrind output:
==73944== Process terminating with default action of signal 11 (SIGSEGV)
==73944== Bad permissions for mapped region at address 0x1D0352A
==73944== at 0xA8A598: zend_hash_iterator_add (zend_hash.c:503)
==73944== by 0x840B07: php_array_walk (array.c:1286)
==73944== by 0x84183B: zif_array_walk (array.c:1407)
==73944== by 0xAB4919: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1250)
==73944== by 0xB2B883: execute_ex (zend_vm_execute.h:55975)
==73944== by 0xB310D5: zend_execute (zend_vm_execute.h:60343)
==73944== by 0xA73DE2: zend_execute_scripts (zend.c:1780)
==73944== by 0x9CD491: php_execute_script (main.c:2480)
==73944== by 0xBEDD26: do_cli (php_cli.c:964)
==73944== by 0xBEE9E5: main (php_cli.c:1333)
But I expected this output instead:
// blank output
To fix this:
array_walk expects get_properties
to return a non-empty refcounted array. Options include:
- Start doing that, e.g. with rebuild_object_properties. Also start to override the
get_properties_for
handler alongside theget_properties
handler to return null - Change behavior of that and other callers of Z_OBJPROP and other uses of get_properties to allow internal classes to return null in handler overrides
- Special case
zend_hash_num_elements(target_hash) == 0
and return early while continuing to freeuserdata
- this should avoid this crash?
// ext/standard/array.c
// static int php_array_walk(
// php_array_walk_context *context, zval *array, zval *userdata, int recursive)
zend_hash_internal_pointer_reset_ex(target_hash, &pos);
ht_iter = zend_hash_iterator_add(target_hash, pos); // this tries to modify the immutable array
// ext/ffi/ffi.c
static HashTable *zend_fake_get_properties(zend_object *obj) /* {{{ */
{
return (HashTable*)&zend_empty_array; // This is a const immutable array
}
/* }}} */
PHP Version
7.4-8.3-dev
Operating System
Any