1183 Commits
Author SHA1 Message Date
Ilija Tovilo 9705fda1bb Merge branch 'PHP-8.6' into master
* PHP-8.6:
  Add NEWS entry
  Avoid state corruption via bailout
2026-10-21 16:34:56 +02:00
Ilija Tovilo d6373dfe15 Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5:
  Add NEWS entry
  Avoid state corruption via bailout
2026-10-21 16:33:23 +02:00
Ilija Tovilo c7273b9ba8 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Add NEWS entry
  Avoid state corruption via bailout
2026-10-21 16:30:04 +02:00
Ilija Tovilo 8a94bb3822 Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3:
  Add NEWS entry
  Avoid state corruption via bailout
2026-10-21 16:27:03 +02:00
Ilija Tovilo c1a5f468d0 Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2:
  Add NEWS entry
  Avoid state corruption via bailout
2026-10-21 16:12:35 +02:00
3584a98bda Avoid state corruption via bailout
- Replace bailout on OOM with UnwindExit
- Properly reset various globals that may be accessed during startup

Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618)
Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619)

Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
Co-authored-by: Jakub Zelenka <bukka@php.net>
Co-authored-by: Nora Dossche <7771979+ndossche@users.noreply.github.com>
Co-authored-by: Nicolas Grekas <nicolas.grekas@gmail.com>
2026-10-21 16:06:22 +02:00
Gina Peter BanyardandArnaud Le Blanc 2f7b01b86c Zend: always populate error pointer on failure of zend_is_callable() (#24435)
* Zend: always populate error pointer on failure

Most of the code base expects an error to be set if a char* is provided, as this used to be always the case. It no longer was the case since the partially supported callables were deprecates as the deprecation could be promoted to an exception in which case we skipped allocating a char*.

The simple fix, allocate a char* even in case of an exception so callers don't need to check if it still NULL. This fixes some error messages at the same time.

* tree: simplify error handling for failed zend_is_callable() calls

* docs: clarify docs for zend_is_callable()

---------

Co-authored-by: Arnaud Le Blanc <365207+arnaud-lb@users.noreply.github.com>
2026-10-20 17:59:02 +01:00
Gina Peter Banyard 40b904316c Zend: add a new zend_call_method_if_exists_ex() (#24082) 2026-10-02 19:15:11 +01:00
Gina Peter Banyard 4d35f4a9c8 Zend: use new zend_object_copy() API 2026-10-01 12:43:56 +01:00
David Carlier ce4ad3e0c3 Merge branch 'PHP-8.6'
* PHP-8.6:
  Fix GH-23896: Assertion failure in zend_call_function() after a throwing deprecation
2026-09-30 05:23:24 +01:00
David Carlier 0520bac249 Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5:
  Fix GH-23896: Assertion failure in zend_call_function() after a throwing deprecation
2026-09-30 05:23:23 +01:00
David Carlier e6775b3fcc Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Fix GH-23896: Assertion failure in zend_call_function() after a throwing deprecation
2026-09-30 05:23:12 +01:00
lazerg a2cdb89100 Fix GH-23896: Assertion failure in zend_call_function() after a throwing deprecation
Since GH-21699, zend_is_callable_check_class() returns false without
setting error when the error handler throws on the self/parent/static
deprecation. zend_call_function() asserted that a failed callable check
always comes with an error message, so calling such a string callback
through call_user_function() (here unserialize_callback_func=parent::...)
aborts on debug builds.

When the check fails with no error, the exception from the handler is
already pending, so zend_call_function() now returns early without
throwing a second one, the same way it does when it is entered with an
exception.

Close GH-23903
2026-09-30 05:23:06 +01:00
Gina Peter Banyard 3884053c04 Zend: rename zend_object* parameter to "this_ptr" for zend_call_* functions (#23989)
To be more explicit in what the zend_object* represents.
2026-09-29 16:20:29 +01:00
Marc 37d0ef5a66 Zend: Remove zend_atomic.[ch] abstraction (#23927) 2026-09-29 16:30:30 +02:00
Tim Düsterhus 83e2394dc7 zend_portability: Simplify definition of ZEND_NORETURN (#23908) 2026-09-29 14:24:35 +02:00
Ilia Alshanetsky 7dc859d75f Merge branch 'PHP-8.5'
* PHP-8.5:
  Zend: release the trampoline when zend_call_function() bails early
2026-09-21 21:16:11 -04:00
Ilia Alshanetsky 027a634280 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Zend: release the trampoline when zend_call_function() bails early
2026-09-21 21:07:25 -04:00
Ilia Alshanetsky d19c413d48 Zend: release the trampoline when zend_call_function() bails early
Two early returns in zend_call_function() skip
zend_release_fcall_info_cache(): the one taken when zend_deprecated_function()
leaves an exception pending, and the one taken when zend_handle_undef_args()
fails. Both leak the trampoline, so a #[\Deprecated] __call() whose
deprecation is promoted to an exception, and a missing required argument on
Closure::__invoke(), each leak 256 bytes per call and trip the
EG(trampoline) assertion in shutdown_executor() on a debug build.

Closes GH-23831
2026-09-21 21:00:24 -04:00
Ilia Alshanetsky 934d4ff95f Pin $this in zend_call_function (#22151)
zend_call_function() ran the callback with fci_cache->object as $this
without holding a reference, so a callback that released the last
reference to its own receiver (an autoloader unregistering itself, a
SQLite3 authorizer calling setAuthorizer(null)) freed $this while its
frame was still executing. Take the reference where the receiver is
selected rather than after argument setup, so the error handlers
reachable from the deprecation notice and the by-reference warning
cannot free it first, and release it on every early exit.

Fixes GH-22060
Fixes GH-22122
2026-09-21 17:32:32 -04:00
Ondřej MirtesandArnaud Le Blanc ba5e9f2517 Cache freed VM stack pages instead of freeing them immediately (#23470)
A call stack whose depth oscillates across a VM stack page boundary
allocates and frees a 256KB page on every oscillation:
zend_vm_stack_extend() on the way down, and the immediate efree() in
zend_vm_stack_free_call_frame_ex() on the way back. Every such
allocation goes through zend_mm_alloc_large(), whose search for
contiguous free pages degrades on a large, fragmented heap - in the
worst case scanning every chunk's free-page bitmap, failing, and paying
an mmap/munmap round-trip per oscillation.

Long-running processes with multi-GB heaps hit this hard. Profiling
PHPStan analysing a large codebase in a single process showed 73-90% of
all CPU time in zend_mm_alloc_pages reached from the
ZEND_INIT_METHOD_CALL handlers, i.e. pure VM stack page churn. An
isolated reproducer (recursion to a fixed depth in a loop, heap
pre-fragmented with interleaved small allocations) runs 15-22x slower
than on a fresh heap.

Keep up to 32 freed standard-size pages in a per-executor free list and
serve zend_vm_stack_new_page() from it; flush the list in
zend_vm_stack_destroy(). Oversized pages (frames larger than the page
size) are still freed eagerly. With the cache, the fragmented-heap
reproducer matches the fresh-heap numbers at every depth, and deep
recursion on a fresh heap improves as well (331.7 -> 229.6us per
oscillation at depth 9000), since even a fast allocator round-trip is
slower than popping a cached page.

Benchmark and reproducer:
https://gist.github.com/ondrejmirtes/1c1bc4894e63ddcb6c58d7bfe59cdb7a

Co-authored-by: Arnaud Le Blanc <arnaud.lb@gmail.com>
2026-09-21 14:03:04 +02:00
Gina Peter Banyard 4e65672bb2 Merge branch 'PHP-8.5' 2026-09-06 14:01:32 +01:00
Gina Peter Banyard 8b287531b8 Merge branch 'PHP-8.4' into PHP-8.5 2026-09-06 13:59:46 +01:00
Benedikt Franke 3ab8be661e Fix GH-23232: lone namespace separator asks the autoloader for an empty class name (#23233)
A class name consisting solely of the namespace separator passed the
length check in zend_lookup_class_ex(), lost its leading backslash and
was then looked up and autoloaded as an empty string. This affected all
entry points using that lookup, e.g. is_callable('\::method') and
class_exists('\').
2026-09-06 13:56:46 +01:00
Weilin Du 7a3785a78b Zend: Use pointer hash lookup for classes 2026-08-16 16:35:06 +08:00
Ilija Tovilo f47cd216e9 Add stateless closure cache
RFC: https://wiki.php.net/rfc/closure-optimizations#stateless_closure_caching

Extracted from GH-19941. Sadly, @DanielEScherzer discovered an edge-case I did
not consider:

    class Foo {
        public function instanceCall() {
            return $this;
        }

        public function test($c) {
            return array_map($c, [1]);
        }
    }

    $foo = new Foo();
    var_dump($foo->test('Foo::instanceCall'));

Here, the internal function array_map() can perform instance calls through a
previous stack frame with just a named closure. Same with ['Foo',
'instanceCall']. That's quite esoteric, but this behavior should first be
deprecated and removed before assuming it isn't being used.

For the time being, merge only the latter half of the RFC. Code with all
relevant functions properly annotated as static will get the full performance
benefit.

Closes GH-23203
2026-08-11 00:30:29 +02:00
Gina Peter Banyard 9518d49da0 Zend: add _ex variants for calling known functions/FCC (#22910)
To permit setting the consumed_arg FCI field
2026-07-28 17:29:11 +01:00
Arnaud Le BlancandJoe Watkins b5fba859ea Partial function application (#20848)
RFC: https://wiki.php.net/rfc/partial_function_application_v2

Co-authored-by: Joe Watkins <krakjoe@php.net>
2026-07-17 10:09:22 +02:00
Ilia Alshanetsky 53b80f07f0 Check the stack limit when calling internal functions (#22545)
zend_call_function invokes an internal callee's handler directly, with no
VM frame and without the stack-limit check the interpreter runs at its call
opcodes. An internal function that recurses through zend_call_function, such
as a self- or mutually-attached SPL iterator, never yields back to the VM,
so nothing bounds the recursion and the C stack overflows into a SEGV.

Check zend_call_stack_overflowed() before pushing the call frame and raise
the usual "Maximum call stack size reached" error on overflow. Running the
check ahead of the frame setup keeps the error path free of teardown.

Fixes GH-15672
Fixes GH-15911
2026-07-07 08:13:14 -04:00
Alexandru Pătrănescu eedda2a03c Add consumed_args callback optimization and apply to array_reduce() for carry to improve performance (GH-21340)
* Add consumed_args support for fcall arguments

* Use consumed_args for array_reduce and some other callback-using functions
2026-05-08 15:42:23 +02:00
Arnaud Le Blanc 2c5dc5d8b1 Add ZEND_ACC2_FORBID_DYN_CALLS
Functions that use zend_forbid_dynamic_call() must be flagged with
ZEND_ACC2_FORBID_DYN_CALLS. In stubs, this is done by using
@forbid-dynamic-calls.

To ensure consistency, we assert that the flag exists in
zend_forbid_dynamic_call(), and we assert that flagged functions thrown after a
dynamic call.

Closes GH-21818
2026-04-22 10:15:59 +02:00
Ben Ramsey e4394946c2 license-update: update Zend copyright name
RFC: https://wiki.php.net/rfc/php_license_update
2026-04-11 21:20:54 -05:00
Ben Ramsey 084a10afef license-update: Zend source headers
RFC: https://wiki.php.net/rfc/php_license_update
2026-04-11 21:20:54 -05:00
Ilija Tovilo 5279185a59 Fix internal return type check with gcov (GH-21653)
ZEND_ASSERT() is a no-op with gcov. Move zend_verify_internal_return_type() out
of ZEND_ASSERT().
2026-04-06 18:24:55 +02:00
Marc Bennewitz f4d9ed1368 Use consistent type for h on call zend_hash_index_* (#19255) 2026-04-06 14:39:41 +01:00
Tim Düsterhus 04f06e8cf2 zend_portability: Remove EMPTY_SWITCH_DEFAULT_CASE() (#20063)
There are several issues with this macro:

- It is incorrectly named: It's not an empty default case. It's an unreachable
  default case.
- It is hiding control flow in its definition, which can be confusing for
  humans and tools (such as Coccinelle) alike, because it looks like it would
  be a statement that belongs to the "current" case rather than opening a new
  one.

Since this macro is exactly as long as explicitly spelling out its definition
(excluding the useless `break;`), it is not even making the code any more
succinct.
2026-04-06 14:46:15 +02:00
David CARLIER 0ada938f88 Zend: Preallocate error buffer with capacity tracking (#20565)
Replace separate num_errors/errors fields with a single struct containing
size, capacity, and a flexible array. The buffer grows by 50% when needed
instead of reallocating on every recorded error.
2026-03-30 18:36:01 +01:00
Tim Düsterhus 7134e69ab2 zend_globals: Embed in_autoload into zend_executor_globals (#21202)
* zend_globals: Embed `in_autoload` into `zend_executor_globals`

Nowadays virtually any PHP application is making use of autoloading, making the
lazy allocation of the `HashTable` struct a needless pointer indirection.

* zend_globals: Rename `in_autoload` to `autoload_current_classnames`

The old name `in_autoload` was somewhat misleading by implying a `bool`ean
value rather than a `HashTable`. Since the previous change to embed the
`HashTable` is breaking anyway, we can also rename it.

* UPGRADING.INTERNALS
2026-02-11 22:53:31 +01:00
Khaled Alam 32bd33983d Remove unreachable code after zend_error_noreturn calls (GH-20983) 2026-02-02 14:14:15 +01:00
Ilija Tovilo 084e409694 Remove zend_exception_save() and zend_exception_restore()
These are leftovers from the pre-PHP-7.0 era. This also implicitly solves
GH-20564 by not clearing exceptions before entering the autoloader.

Closes GH-20256
Fixes GH-20564
2026-01-16 20:18:51 +01:00
Arnaud Le Blanc 626f3c3c7c Unify arg info representation for internal and user functions
The arg_info member of zend_function is now always a zend_arg_info*. Before,
it was a zend_internal_arg_info* on internal functions, unless the
ZEND_ACC_USER_ARG_INFO flag was set.

Closes GH-19022
2025-12-15 16:50:49 +01:00
Gina Peter Banyard 7815ab9b22 Zend: add const qualifiers when possible for _zend_execute_data.func related uses (#20263)
The initial motivation was to see if it is possible to make the `func` field of `_zend_execute_data` constant.

For various reasons, this is not possible, but the added `const` qualifiers during this exploration remain useful.
2025-10-29 13:22:56 +00:00
Gina Peter Banyard 005d04aa96 zend_call_function: emit function deprecation before setting up call frame (#20264) 2025-10-23 16:30:46 +01:00
Ilija Tovilo 74c697cfaa Merge branch 'PHP-8.5'
* PHP-8.5:
  Don't bail when closing resources on shutdown
2025-10-14 22:20:13 +02:00
Ilija Tovilo 19a1600868 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Don't bail when closing resources on shutdown
2025-10-14 22:20:00 +02:00
Ilija Tovilo 55f4d4c909 Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3:
  Don't bail when closing resources on shutdown
2025-10-14 22:19:46 +02:00
Ilija Tovilo e6e39e680e Don't bail when closing resources on shutdown
Fixes GH-19844
Closes GH-19849
2025-10-14 22:19:17 +02:00
Ilija Tovilo 28fd7597ba Add first-class callable cache
This cache is implemented in two levels: A EG(callable_convert_cache) global
that maps zend_function pointers to a shared callable instance, and a
CALLABLE_CONVERT cache slot to remember the result of the hash table lookup.

Fixes GH-19754
Closes GH-19863
2025-10-03 01:04:56 +02:00
Gina Peter Banyard ec31437973 Zend/zend_execute_API.c: use uint32_t type instead of int 2025-09-29 14:59:09 +01:00
Gina Peter Banyard 2f6afda40b Zend/zend_execute_API.c: reduce variable scope 2025-09-29 14:59:09 +01:00