TysonAndre
Repos
165
Followers
117

Phan is a static analyzer for PHP. Phan prefers to avoid false-positives and attempts to prove incorrectness rather than correctness.

5401
346

Uniqush is a free and open source software system which provides a unified push service for server side notification to apps on mobile devices.

1480
194

Igbinary is a drop in replacement for the standard php serializer.

738
59

Runkit that (mostly) works in PHP7! (method and function manipulation)

178
28

Phan - PHP Static Analysis for VS Code

23
3

A fast, light-weight proxy for memcached and redis

C
11732
1943

Events

closed issue
Wordpress cached data unserialized as string instead of array after switching redis-cache-pro from standard serializer to igbinary

lighttpd 1.4.69, PHP-fpm 8.2.3, debian 11, 10.5.18-MariaDB, redis-cache-pro - compression lz4 All packages are installed via apt

php info igbinary support - enabled igbinary version 3.2.13 redis - Available serializers php, json, igbinary session - Registered serializer handlers php_serialize php php_binary igbinary msgpack session.serialize_handler igbinary igbinary

php -i | grep igbinary /etc/php/8.2/cli/conf.d/20-igbinary.ini, igbinary igbinary support => enabled igbinary version => 3.2.13 igbinary APCu serializer ABI => 0 igbinary session support => yes igbinary.compact_strings => On => On igbinary support => yes Available serializers => php, json, igbinary Registered serializer handlers => php_serialize php php_binary igbinary msgpack session.serialize_handler => igbinary => igbinary

If you use php as the default serializer in the configuration, then everything works very quickly. But I read that igbinary_serialize works several times faster?

define( 'WP_REDIS_CONFIG', [ 'token' => '', 'host' => '127.0.0.1', 'port' => 6379, 'database' => 5, 'maxttl' => 3600 * 24 * 7, 'timeout' => 0.5, 'read_timeout' => 0.5, 'retry_interval' => 10, 'retries' => 3, //'serializer' => 'igbinary', 'compression' => 'lz4', 'async_flush' => true, 'client' => 'phpredis', 'split_alloptions' => true, 'shared' => true, 'prefetch' => true, 'debug' => false, 'save_commands' => false, ]); define('WP_REDIS_DISABLED', getenv('WP_REDIS_DISABLED') ?: false);

But when I turn on 'serializer' = > 'igbinary', in the config, I get a critical error in Wordpress.

2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:PHP message: PHP Fatal error: Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, string given in /www/free/wp-includes/class-wp-roles.php:291 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:Stack trace: 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#0 /www/free/wp-includes/class-wp-roles.php(291): array_keys() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#1 /www/free/wp-includes/class-wp-roles.php(332): WP_Roles->init_roles() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#2 /www/free/wp-includes/class-wp-roles.php(91): WP_Roles->for_site() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#3 /www/free/wp-settings.php(542): WP_Roles->__construct() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#4 /www/free/wp-config.php(101): require_once('...') 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#5 /www/free/wp-load.php(50): require_once('...') 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#6 /www/free/wp-admin/admin-post.php(19): require_once('...') 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#7 {main} 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr: thrown in /www/free/wp-includes/class-wp-roles.php on line 291; PHP message: PHP Fatal error: Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, string given in /www/free/wp-includes/class-wp-roles.php:291 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:Stack trace: 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#0 /www/free/wp-includes/class-wp-roles.php(291): array_keys() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#1 /www/free/wp-includes/class-wp-roles.php(332): WP_Roles->init_roles() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#2 /www/free/wp-includes/class-wp-roles.php(91): WP_Roles->for_site() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#3 /www/free/wp-includes/capabilities.php(997): WP_Roles->__construct() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#4 /www/free/wp-includes/class-wp-user.php(510): wp_roles() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#5 /www/free/wp-includes/class-wp-user.php(877): WP_User->get_role_caps() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#6 /www/free/wp-includes/class-wp-user.php(178): WP_User->for_site() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#7 /www/free/wp-includes/pluggable.php(109): WP_User->init() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#8 /www/free/wp-includes/pluggable.php(737): get_user_by() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#9 /www/free/wp-includes/class-wp-hook.php(308): wp_validate_auth_cookie() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#10 /www/free/wp-includes/plugin.php(205): WP_Hook->apply_filters() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#11 /www/free/wp-includes/user.php(3604): apply_filters() 2023-03-08 21:09:47: (mod_fastcgi.c.449) FastCGI-stderr:#12 /www/free/wp-includes/p... 2023-03-08 21:09:49: (mod_fastcgi.c.449) FastCGI-stderr:PHP message: PHP Fatal error: Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, string given in /www/free/wp-includes/class-wp-roles.php:291

Created at 2 weeks ago
issue comment
WP_REDIS with serializer igbinary - PHP Fatal error

But when I turn on 'serializer' = > 'igbinary', in the config, I get a critical error in Wordpress.

Did you restart apache?

Created at 2 weeks ago
issue comment
WP_REDIS with serializer igbinary - PHP Fatal error

Does the issue happen with an empty cache?

Are you running more than one server? If so, did you upgrade all of the servers? Does the issue happen all of the time?

What redis-cache-pro version is this?

Created at 2 weeks ago
issue comment
WP_REDIS with serializer igbinary - PHP Fatal error

Which of the advanced options are you using? https://github.com/rhubarbgroup/redis-cache/blob/77fcd714a58806819d85c4a017a8588e98f5fec2/README.md - WP_REDIS_SERIALIZER or WP_REDIS_IGBINARY? (I assume it's WP_REDIS_SERIALIZER and somehow extracted from WP_REDIS_CONFIG)

Does the issue happen with an empty cache?

Created at 2 weeks ago
issue comment
WP_REDIS with serializer igbinary - PHP Fatal error

Never mind, it isn't that, it'd return false if igbinary is loaded.

What are the values of WP_REDIS_* constants you have set up or the cache configuration?

What were your original settings (e.g. did compression change?)

Created at 2 weeks ago
issue comment
WP_REDIS with serializer igbinary - PHP Fatal error

https://github.com/rhubarbgroup/redis-cache/blob/83c771dfc5bedc807133330080598553deb65dd9/includes/object-cache.php#L2691-L2698

Oh. Actually, it turned out to be obvious. It's a bug in redis-cache-pro. redis-cache-pro is unconditionally trying to unserialize the data it retrieved from redis (PHP serialize()) with igbinary (igbinary unserialize()). That fails, so it returns the original string, probably of the form a:...{...}

It wouldn't happen in installations that started with an empty redis cache or cleared it (not sure if that would cause issues for you)

It should be doing something similar to phpredis instead, and checking if substr( $original, 0, 4) === "\0\0\0\0" or something similar, but it isn't.

        case REDIS_SERIALIZER_IGBINARY:
#ifdef HAVE_REDIS_IGBINARY
            /*
             * Check if the given string starts with an igbinary header.
             *
             * A modern igbinary string consists of the following format:
             *
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
             * | header (4) | type (1) | ... (n) |  NUL (1) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
             *
             * With header being either 0x00000001 or 0x00000002
             * (encoded as big endian).
             *
             * Not all versions contain the trailing NULL byte though, so
             * do not check for that.
             */
            if (val_len < 5
                    || (memcmp(val, "\x00\x00\x00\x01", 4) != 0
                    && memcmp(val, "\x00\x00\x00\x02", 4) != 0))
            {
                /* This is most definitely not an igbinary string, so do
                   not try to unserialize this as one. */
                break;
            }

            ret = !igbinary_unserialize((const uint8_t *)val, (size_t)val_len, z_ret);
#endif
            break;
Created at 2 weeks ago
issue comment
WP_REDIS with serializer igbinary - PHP Fatal error

Can you create a minimal, self-contained repo or example file to reproduce this issue? (If possible, the an object/array which when serialized with igbinary, results in an array becoming a non-array)

I'm not familiar with where the redis cache is being used in https://github.com/WordPress/WordPress/blob/master/wp-includes/class-wp-roles.php

I'm also not familiar with https://en-ca.wordpress.org/plugins/redis-cache/ , and a standalone example would be easier to work with

Also, what is the string it's being called with? Can you include it or steps to create a similar string that reproduces the issue?

Created at 2 weeks ago
push

Fix NEWS.md markdown

Use actions/checkout v3 with Node.js 16

Created at 3 weeks ago
issue comment
Support (partial) inheritance of @throws annotations

As far as I can see, phan does not have an issue type for @throws annotations on methods that don't actually throw those exceptions (because I guess it might be hard to prove statically).

Yes, that and the fact that user @throws may be API documentation for subclasses, or user code being incomplete.

I think this might be achieved by keeping two separate lists for @throws that were found in the method's own docblock, and for the ones inherited from an ancestor.

A non-standard @throws never might work, though I think a class name is usually expected.

Two separate lists makes sense for analyzing the implementers and callers differently.

Created at 3 weeks ago
issue comment
Ignore links (symlinks/hardlinks)

I have projects set up that rely on symlinks (e.g. where multiple applications depend on the same library as a symlinked folder)

It'd be better to have this as a .phan/config.php setting such as 'ignore_symlinks' defaulting to false (see src/Phan/Config.php)

Created at 3 weeks ago
push

Use release version of PHP 8.2 in workflows

Merge pull request #4766 from bobvandevijver/patch-1

Use release version of PHP 8.2 in workflows

Created at 3 weeks ago
pull request closed
Use release version of PHP 8.2 in workflows
Created at 3 weeks ago
closed issue
Release 5.4.2 does not provide phar

the latest release does not attach a phar for direct execution

Created at 3 weeks ago
issue comment
Release 5.4.2 does not provide phar

Fixed by attaching phan.phar and phan.phar.asc built from the 5.4.2 release tag

Created at 3 weeks ago
create tag
TysonAndre create tag 3.2.14
Created at 1 month ago
delete branch
TysonAndre delete branch uintptr_t-cleanup
Created at 1 month ago
closed issue
Build is failing with php-src master
...
mkdir:  cc -I. -I/tmp/pear/temp/igbinary -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/include -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/main -I/tmp/pear/temp/igbinary -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O0 -D_GNU_SOURCE -g -O0 -O2 -Wall -Wpointer-arith -Wcast-align -Wwrite-strings -Wswitch -DZEND_COMPILE_DL_EXT=1 -c /tmp/pear/temp/igbinary/src/php7/igbinary.c -MMD -MF src/php7/igbinary.dep -MT src/php7/igbinary.lo  -fPIC -DPIC -o src/php7/.libs/igbinary.o
cannot create directory ‘src/php7/.libs’: File exists
 cc -I. -I/tmp/pear/temp/igbinary -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/include -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/main -I/tmp/pear/temp/igbinary -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O0 -D_GNU_SOURCE -g -O0 -O2 -Wall -Wpointer-arith -Wcast-align -Wwrite-strings -Wswitch -DZEND_COMPILE_DL_EXT=1 -c /tmp/pear/temp/igbinary/src/php7/hash_si.c -MMD -MF src/php7/hash_si.dep -MT src/php7/hash_si.lo  -fPIC -DPIC -o src/php7/.libs/hash_si.o
/bin/sh /tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/libtool --mode=compile cc -I. -I/tmp/pear/temp/igbinary -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/include -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/main -I/tmp/pear/temp/igbinary -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib  -DHAVE_CONFIG_H  -g -O0 -D_GNU_SOURCE   -g  -O0 -O2 -Wall -Wpointer-arith -Wcast-align -Wwrite-strings -Wswitch -DZEND_COMPILE_DL_EXT=1 -c /tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c -o src/php7/hash_si_ptr.lo  -MMD -MF src/php7/hash_si_ptr.dep -MT src/php7/hash_si_ptr.lo
 cc -I. -I/tmp/pear/temp/igbinary -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/include -I/tmp/pear/temp/pear-build-defaultuserekdIGc/igbinary-3.2.13/main -I/tmp/pear/temp/igbinary -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O0 -D_GNU_SOURCE -g -O0 -O2 -Wall -Wpointer-arith -Wcast-align -Wwrite-strings -Wswitch -DZEND_COMPILE_DL_EXT=1 -c /tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c -MMD -MF src/php7/hash_si_ptr.dep -MT src/php7/hash_si_ptr.lo  -fPIC -DPIC -o src/php7/.libs/hash_si_ptr.o
In file included from /tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c:20:
/tmp/pear/temp/igbinary/src/php7/hash_ptr.h:34:9: error: unknown type name 'zend_uintptr_t'
   34 |         zend_uintptr_t key; /**< The key: The address of a pointer, casted to an int (won't be dereferenced). */
      |         ^~~~~~~~~~~~~~
/tmp/pear/temp/igbinary/src/php7/hash_ptr.h:102:64: error: unknown type name 'zend_uintptr_t'
  102 | size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value);
      |                                                                ^~~~~~~~~~~~~~
/tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c:25:47: error: unknown type name 'zend_uintptr_t'; did you mean 'tsrm_uintptr_t'?
   25 | inline static uint32_t inline_hash_of_address(zend_uintptr_t ptr) {
      |                                               ^~~~~~~~~~~~~~
      |                                               tsrm_uintptr_t
/tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c: In function 'hash_si_ptr_rehash':
/tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c:110:39: warning: implicit declaration of function 'inline_hash_of_address' [-Wimplicit-function-declaration]
  110 |                         uint32_t hv = inline_hash_of_address(old_data[i].key) & mask;
      |                                       ^~~~~~~~~~~~~~~~~~~~~~
/tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c: At top level:
/tmp/pear/temp/igbinary/src/php7/hash_si_ptr.c:133:64: error: unknown type name 'zend_uintptr_t'
  133 | size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value) {
      |                                                                ^~~~~~~~~~~~~~
make: *** [Makefile:216: src/php7/hash_si_ptr.lo] Error 1
make: *** Waiting for unfinished jobs....
ERROR: `make -j2' failed

caused probably by https://github.com/php/php-src/pull/10597

Created at 1 month ago

Release 3.2.14: Fix php 8.3 compatibility error

Fixes #374

Merge pull request #375 from TysonAndre/uintptr_t-cleanup

Release 3.2.14: Fix php 8.3 compatibility error

Created at 1 month ago
pull request closed
Release 3.2.14: Fix php 8.3 compatibility error

Fixes #374

Created at 1 month ago
pull request opened
Release 3.2.14: Fix php 8.3 compatibility error

Fixes #374

Created at 1 month ago

Release 3.2.14: Fix php 8.3 compatibility error

Fixes #374

Created at 1 month ago
create branch
TysonAndre create branch uintptr_t-cleanup
Created at 1 month ago
issue comment
Build is failing with php-src master

Even in php 7.0, it's typedef uintptr_t zend_uintptr_t; in Zend/zend_types.h, so it's straightforward to change, even if headers were meant to be public (though src/php7/hash_ptr.h is an internal implementation detail)

Created at 1 month ago
opened issue
Test out cswisstable for unserialization/serialization data structures

https://github.com/google/cwisstable (or any other library that allows customization while supporting C compilers without C++ requirement)

CWISS_AllocPolicy should be used to make it use emalloc/efree

E.g. for ref_props when unserializing typed properties. Followup to #371

Created at 1 month ago
issue comment
C apis for efficiently adding/checking if a pointer is in a HashTable, reducing hash collisions?

This issue ultimately boils down to the usage of unhashed integers as keys, which is an issue that crops up everywhere. The only real solution is built-in integer HashTable key hashing like siphash or similar. Does it really make sense to add extra APIs for this case instead of addressing the underlying problem?

Changing the hashing everywhere would probably negatively affect benchmarks for common use cases (and worsen cache locality for cases such as associative arrays with a few gaps)

As an alternative, @iluuu1994 mentioned https://github.com/google/cwisstable existed in another PR https://github.com/google/cwisstable https://github.com/google/cwisstable#compatibility-warnings

  • Maybe embed it in a C file and expose wrapper APIs for a fixed set of common cases such as unordered uintptr_t -> void* with no garbage collection?
  • The memory savings (and better cache locality) would be convenient when we know the types (e.g. uintptr_t and int)
  • I believe cswisstable has a final hash step that will evenly distribute the input keys
  • https://github.com/google/cwisstable/blob/main/cwisstable/policy.h has CWISS_AllocPolicy allowing the use of emalloc/efree

There's use cases such as the destructor and ordering where HashTable would do better.

I haven't tried it yet, but meant to try that for igbinary to see the performance impact for data structures for serialization and unserialization


Getting agreement on what to add to the public API and whether it's necessary seems like it might be difficult when HashTable is good enough for use cases when used properly (for small amounts of data, cswisstable wasn't faster, but large amounts would be noticeable)

Created at 1 month ago
delete branch
TysonAndre delete branch fix-reset-ffi-crash
Created at 1 month ago
closed issue
`array_walk($ffiInstance, function () {})` and `reset($ffiInstance)` crashes due to expecting mutable array

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:

  1. Start doing that, e.g. with rebuild_object_properties. Also start to override the get_properties_for handler alongside the get_properties handler to return null
  2. 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
  3. Special case zend_hash_num_elements(target_hash) == 0 and return early while continuing to free userdata - 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

Created at 1 month ago

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 d9651a941915eb5fb5ad557090b65256fd8509b6 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 https://github.com/php/php-src/issues/9697#issuecomment-1273613175

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.

Merge branch 'PHP-8.1' into PHP-8.2

Merge branch 'PHP-8.2'

Created at 1 month ago

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 d9651a941915eb5fb5ad557090b65256fd8509b6 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 https://github.com/php/php-src/issues/9697#issuecomment-1273613175

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.

Merge branch 'PHP-8.1' into PHP-8.2

Created at 1 month ago