* PHP-8.6:
[`%pS` migration] Use `%pS` in ext/spl/spl_observer.c
[`%pS` migration] Use `%pS` in ext/spl/spl_iterators.c
[`%pS` migration] Use `%pS` in ext/spl/spl_heap.c
[`%pS` migration] Use `%pS` in ext/spl/spl_directory.c
[`%pS` migration] Use `%pS` in ext/spl/spl_array.c
[`%pS` migration] Use `%pS` in ext/spl/php_spl.c
`return new \ArrayIterator($this->items);` is the usual getIterator() implementation of Twig nodes, Symfony bags or Doctrine collections, and profiling a foreach over such objects shows zend_parse_parameters() taking about 180 instructions per ArrayIterator::__construct() call. This switches both constructors and the ArrayAccess methods (offsetExists(), offsetGet(), offsetSet(), offsetUnset(), append()) to fast ZPP. Accepted types, error messages and deprecations don't change.
Instructions per operation (callgrind, -O2 build, arrays of 0/5/100 elements): new ArrayIterator() -181, i.e. -16.5%/-13.8%/-6.6%, and -11.4%/-4.7%/-0.4% when followed by foreach. new ArrayObject() -199, i.e. -17.8%/-14.9%/-7.2%, and -8.7%/-4.2%/-0.4% with foreach. offsetGet() and friends called as methods, e.g. via parent::offsetSet() in subclasses, are 39% to 43% cheaper. Walking Twig's node trees with foreach (17.6k nodes): -4.2% per round. The binary grows by 472 bytes of text.
Headers required by the generated code (zend_attributes.h, zend_constants.h, zend_enum.h) are collected during generation and emitted as includes at the top of the arginfo file, with the same preprocessor conditions and PHP version guards as the code that needs them.
Removes the manual zend_attributes.h and zend_enum.h includes from sources that only needed them for the arginfo file they include.
spl_array_method() caches the backing HashTable pointer across a
user-supplied comparator (uasort/uksort and the sort handlers). The
comparator can re-enter __construct() or __unserialize(), which route
through spl_array_set_array() and swap intern->array out from under the
cached pointer, leaving the post-sort cleanup to release and dereference
freed memory. Mirror the nApplyCount guard the other mutators already
use so replacing the backing store during a sort throws instead.
Closes GH-22310
* ext/*: Make `X_from_obj(zend_object *obj)` functions macros
With the introduction of the `ZEND_CONTAINER_OF()` macro we can now preserve
whether or not the `zend_object *` is `const` when extracting the
class-specific struct. This change will allow to use `const zend_object *` in
more locations.
Changes performed with Coccinelle followed by some manual cleanup for comment
and whitespace formatting:
@a@
attribute name zend_always_inline;
type T;
identifier obj;
identifier f;
typedef zend_object;
@@
T* f(zend_object *obj) { return ZEND_CONTAINER_OF(obj, T, std); }
+ #define f(obj) ZEND_CONTAINER_OF(obj, T, std)
@@
identifier a.f;
@@
- f(...) { ... }
@b@
attribute name zend_always_inline;
type T;
identifier obj;
identifier f;
typedef zend_object;
@@
T* f(zend_object *obj) { return ZEND_CONTAINER_OF(obj, T, zo); }
+ #define f(obj) ZEND_CONTAINER_OF(obj, T, zo)
@@
identifier b.f;
@@
- f(...) { ... }
* sockets: Fix build
* odbc: Fix build
* zend_portability: Add `ZEND_CONTAINER_OF()`
* tree-wide: Use `ZEND_CONTAINER_OF()`
Changes made with Coccinelle:
@@
type T_container;
identifier member;
expression e;
@@
- (T_container *)(((char *)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
@@
type T_container;
identifier member;
expression e;
typedef uintptr_t;
@@
- (T_container *)(((uintptr_t)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
@@
type T_container;
identifier member;
expression e;
@@
- (const T_container *)(((char *)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
@@
type T_container;
identifier member;
expression e;
typedef uintptr_t;
@@
- (const T_container *)(((uintptr_t)(e)) - offsetof(T_container, member))
+ ZEND_CONTAINER_OF(e, T_container, member)
* bcmath: Fix `get_bcmath_number_from_obj()` const-correctness
A follow-up change to the new `ZEND_CONTAINER_OF()` macro will preserve the
`const`-ness of the input pointer. By wrapping this macro inside a macro rather
an an inline function we can preserve the `const`-ness across all layers.
* zend_portability: Keep `const`-ness in `ZEND_CONTAINER_OF()`
* zend_portability: Add C++ version to `ZEND_CONTAINER_OF()`
The fix for this was to take hold of a pointer of the bucket, something that should not be done as it causes memory corruptions
Closes GH-21532, GH-21520, GH-21499
* PHP-8.4:
Fix GH-18309: ipv6 filter integer overflow
Fix GH-18304: Changing the properties of a DateInterval through dynamic properties triggers a SegFault
* PHP-8.3:
Fix GH-18309: ipv6 filter integer overflow
Fix GH-18304: Changing the properties of a DateInterval through dynamic properties triggers a SegFault
For dynamic fetches the cache_slot will be NULL, so we have to check for
that when resetting the cache. For zip and xmlreader this couldn't
easily be tested because of a lack of writable properties.
Closes GH-18307.
The cache slot for FETCH_OBJ_W in function `test` is primed with the
class for C. The next call uses a simplexml instance and reuses the same
cache slot. simplexml's get_property_ptr handler does not use the cache
slot, so the old values remain in the cache slot. When
`zend_handle_fetch_obj_flags` is called this is not guarded by a check
for the class entry. So we end up using the prop_info from the property
C::$a instead of the simplexml property.
This patch adds a reset to the cache slots in the property address fetch
code and also in the extensions with a non-standard reference handler.
This keeps the run time cache consistent and avoids the issue without
complicating the fast paths.
Closes GH-17739.
* PHP-8.4:
Fix GH-17307: Internal closure causes JIT failure
Generate inline frameless icall handlers only if the optimization level is set to inline
Fix GH-15981: Segfault with frameless jumps and minimal JIT
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.
SplFixedArray should've never get supported in ArrayObject because it's
overloaded, and so that breaks assumptions. This regressed in c4ecd82f.
Closes GH-15947.
The zend_object.properties HashTable needs to be built just in time by calling
rebuild_object_properties() on the object before accessing it. Normally this is
done automatically in zend_std_get_properties(), but we do it manually in a few
places.
In this change I introduce an inline variant of zend_std_build_properties(), and
refactor these places to use it instead of calling rebuild_object_properties()
manually.
rebuild_object_properties() renamed as rebuild_object_properties_internal(), to
enforce usage of zend_std_get_properties() or zend_std_build_properties_ex().
Closes GH-14996