1289 Commits
Author SHA1 Message Date
ndossche 8867746907 Merge branch 'PHP-8.6'
* PHP-8.6:
  Fix use-after-free in Randomizer::shuffleArray() when the engine throws
2026-10-28 08:25:23 +01:00
ndossche 30bcf4bd89 Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5:
  Fix use-after-free in Randomizer::shuffleArray() when the engine throws
2026-10-28 08:25:17 +01:00
ndossche dbd6ed433d Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Fix use-after-free in Randomizer::shuffleArray() when the engine throws
2026-10-28 08:24:57 +01:00
Martin Mirchev 3a8bcb6d18 Fix use-after-free in Randomizer::shuffleArray() when the engine throws
php_array_data_shuffle() first compacts the holes of a packed array and
only then updates nNumUsed. When the engine threw in between, the stale
tail slots were still counted, so the moved values were released twice
when the copied array was destroyed. Update nNumUsed right after the
compaction.

Closes GH-24553.
2026-10-28 08:24:25 +01:00
Arnaud Le Blanc 947c556ba2 Assert that destroyed hash tables are not in GC buffer (#24739) 2026-10-27 16:24:23 +01:00
Weilin Du c47875f47b Merge branch 'PHP-8.6'
* PHP-8.6:
  Fix GH-24552: Use ASCII case folding in string comparisons (#24558)
2026-10-27 21:23:26 +08:00
Weilin Du 04a5da0ab6 Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5:
  Fix GH-24552: Use ASCII case folding in string comparisons (#24558)
2026-10-27 21:23:12 +08:00
Weilin Du 6a020d606e Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Fix GH-24552: Use ASCII case folding in string comparisons (#24558)
2026-10-27 21:22:44 +08:00
lazergandJon Surrell 872c6e19c4 Fix GH-24552: Use ASCII case folding in string comparisons (#24558)
PHP 8.2 made case-insensitive comparisons ASCII-only, but ksort() and
krsort() with SORT_STRING | SORT_FLAG_CASE and substr_compare() with
case_insensitive=true still used the locale-sensitive _l variants.
These call tolower() and depend on LC_CTYPE.

Use zend_binary_strcasecmp() and zend_binary_strncasecmp(), consistent
with sort() and strncasecmp(), so these comparisons also use ASCII case
folding regardless of the current locale.

Fixes #24552

Co-authored-by: Jon Surrell <sirreal@users.noreply.github.com>

Closes #24558
2026-10-27 21:21:44 +08:00
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
mehmetcansahin 6fc4017a94 ext/standard: Optimize array_chunk() by filling packed chunks directly
When $preserve_keys is not passed, every chunk is a list of at most
$size elements, so each chunk can be built with ZEND_HASH_FILL_PACKED
instead of one zend_hash_next_index_insert() call per element.

Close GH-23556
2026-10-08 06:30:43 +01:00
Gina Peter Banyard d2d54ce336 std: refactor php_array_find() to only use FCC
This prevents refetching potential trampoline over and over again.
2026-10-06 16:19:21 +01:00
mehmetcan a8caefcafb array_splice(): Presize the result when nothing is removed (#23886)
The output hash was sized for the replacement only, so copying the kept
input elements grew it by doubling. Size it for the final element count.
2026-09-24 19:22:09 +01:00
Weilin Du 82d91d49d8 ext/standard: Optimize result-row construction in array_map() with a null callback (#23809)
In this case we just init each value once.
2026-09-23 12:55:31 +08:00
Weilin DuandDavid CARLIER 5d24c8bd60 ext/standard: Optimize array_column() (#23786)
Just move some numeric-string key normalization stuff out
of the main loop. Also return early for empty input.

Co-authored-by: David CARLIER <devnexen@gmail.com>
2026-09-21 00:11:45 +08:00
Weilin Du 1849f03afc ext/standard: Optimize integer key insertion in array_change_key_case()
Integer keys are copied unchanged from the input and remain unique in the
new result. Use zend_hash_index_add_new() to avoid redundant checks.
2026-09-17 09:38:17 +08:00
Weilin Du 8b0088a41d Merge branch 'PHP-8.5'
* PHP-8.5:
  Fix GH-23576: array_keys() on an empty array returns a non-zero next index (#23577)
2026-09-07 13:29:26 +08:00
Weilin Du 752c9ff6e9 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Fix GH-23576: array_keys() on an empty array returns a non-zero next index (#23577)
2026-09-07 13:29:11 +08:00
Lazizbek Ergashev 4365896084 Fix GH-23576: array_keys() on an empty array returns a non-zero next index (#23577)
`array_keys()` reused the input array when it was empty. For an array
that was previously populated, this preserved the next free index and
caused later appends to start at a non-zero key, even though
`array_keys()` returns a list.

Return a fresh empty array, matching `array_values()`, and cover both
previously populated and fresh empty arrays across all argument forms.

Closes #23577
2026-09-07 13:28:55 +08:00
David Carlier a482d662b1 Merge branch 'PHP-8.5'
* PHP-8.5:
  ext/standard: array_merge_recursive() fix leak.
2026-08-18 12:28:33 +01:00
David Carlier 067408fd2e Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  ext/standard: array_merge_recursive() fix leak.
2026-08-18 12:28:30 +01:00
David Carlier 4c71b4e58e ext/standard: array_merge_recursive() fix leak.
object to array conversion failure leaked the temporary zval.
while at it, fix reverse expectation on a failed neighbour insertion.

Close GH-23340
2026-08-18 12:28:26 +01:00
Arnaud Le Blanc b6bd738e45 Merge branch 'PHP-8.5'
* PHP-8.5:
  Add a stack limit check in php_count_recursive() (#23197)
2026-08-11 19:01:51 +02:00
Arnaud Le Blanc b5bca194e7 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Add a stack limit check in php_count_recursive() (#23197)
2026-08-11 19:01:37 +02:00
Lazizbek Ergashev c6d19577eb Add a stack limit check in php_count_recursive() (#23197) 2026-08-11 19:01:11 +02:00
Gina Peter Banyard 7e0d5c75e7 standard: deprecate passing an object to array_walk{_recursive}()
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_array_parameter_of_array_walk_and_array_walk_recursive
2026-08-10 18:21:19 +01:00
Arnaud Le Blanc 6f20e7003c Merge branch 'PHP-8.5'
* PHP-8.5:
  Add a stack limit check in php_compact_var() (#23126)
2026-08-10 13:12:34 +02:00
Arnaud Le Blanc daf60b4267 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Add a stack limit check in php_compact_var() (#23126)
2026-08-10 13:11:58 +02:00
Lazizbek Ergashev 71a1244507 Add a stack limit check in php_compact_var() (#23126)
php_compact_var() recurses once per nesting level with no stack check, so passing a deeply nested array to compact() exhausts the native stack and the process dies with a segfault.

This adds the same stack limit check ext/standard already uses in var.c and http.c, so the call throws an Error instead of crashing.

Fixes GH-23115
2026-08-10 13:10:59 +02:00
Arnaud Le Blanc 6ff0dcc066 Merge branch 'PHP-8.5'
* PHP-8.5:
  Add a stack limit check in php_array_replace_recursive (#23124)
  Add a stack limit check in php_array_walk() (#23125)
2026-08-10 12:01:23 +02:00
Arnaud Le Blanc 5ae3f54aa3 Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Add a stack limit check in php_array_replace_recursive (#23124)
  Add a stack limit check in php_array_walk() (#23125)
2026-08-10 12:01:05 +02:00
Lazizbek Ergashev af1abdfc34 Add a stack limit check in php_array_replace_recursive (#23124)
php_array_replace_recursive() recurses once per nesting level with no stack check, so array_replace_recursive() on a deeply nested array exhausts the native stack and the process dies with a segfault.

Fixes GH-23113
2026-08-10 11:59:11 +02:00
Lazizbek Ergashev 69d5f1b5d2 Add a stack limit check in php_array_walk() (#23125)
php_array_walk() recurses once per nesting level with no stack check, so array_walk_recursive() on a deeply nested array exhausts the native stack and the process dies with a segfault.

This adds the same stack limit check ext/standard already uses in var.c and http.c, so the call throws an Error instead of crashing. The existing GC_IS_RECURSIVE guard only covers self-referential arrays, not plain deep nesting.

Fixes GH-23111
2026-08-10 11:57:00 +02:00
mehmetcan e9deb0af19 Optimize array_intersect() using hash-based matching (#23019) 2026-08-06 13:12:21 +02:00
Calvin Buckley 02334db9bb Remove php_error_docref_unchecked (#23042)
* standard: remove sole user of php_error_docref_unchecked

After GH-22390 was merged, we can now use a %pS format specifier for
zend_string without having to use the unchecked variant (so that gcc et
al doesn't complain that %S should be for wchar_t*).

* main: Remove php_error_docref_unchecked

There are no external users AFAIK, and now no internal users.
2026-08-04 18:08:07 -03:00
Ilia Alshanetsky 75cdbcd40b Merge branch 'PHP-8.5'
* PHP-8.5:
  Fix GH-22678: array_multisort() use-after-free on mutating comparator
2026-07-12 20:38:02 -04:00
Ilia Alshanetsky 6493ea617a Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
  Fix GH-22678: array_multisort() use-after-free on mutating comparator
2026-07-12 20:37:35 -04:00
Ilia Alshanetsky 1e9f56cdb4 Fix GH-22678: array_multisort() use-after-free on mutating comparator
array_multisort() snapshotted each input array's buckets without holding a
reference, then ran a comparator that under SORT_STRING invokes
Stringable::__toString(); a callback that unset or reassigned the array freed
its backing store and elements mid-sort, a use-after-free read in the
comparator and a write-back through the freed table during the restructure.
Hold a reference on each input HashTable for the duration of the sort and
restructure the cached tables, mirroring zend_array_sort_ex() (GH-16648).
HT_ALLOW_COW_VIOLATION allows the in-place repack under the held reference.

Fixes GH-22678
Closes GH-22680
2026-07-12 20:21:37 -04:00
mehmetcan 9060fd3366 Move min/max array fallback into array.c (#22147) 2026-06-29 17:43:29 +01:00
Weilin Du 7c86d86d26 Reuse existing Zend parameter error helpers for standard error paths (#22033)
Cleaning up the manually constructed standard parameter errors to use existing Zend helpers in bulk. This enhance readability and align with how those errors have been thrown in most places.
2026-06-13 15:20:38 +08:00
mehmetcan a7915341e5 [ext/standard] Specialize array_sum()/array_product() for long arrays (#21787)
* [ext/standard] Specialize array_sum()/array_product() for long arrays

The per-element cost of array_sum() and array_product() is dominated by
the add_function/mul_function call dispatch. Add a specialized fast
path for the IS_LONG + IS_LONG case that inlines overflow-aware
arithmetic via fast_long_add_function() and ZEND_SIGNED_MULTIPLY_LONG()
-- the same engine helpers that add_function_fast() dispatches to
internally. The fast path applies to both packed and hash arrays.

On overflow, non-IS_LONG entries, objects, resources or strings,
execution falls through to the generic path in php_array_binop_apply(),
so the PHP 8.3 warning behavior, operator overloading and BC casts for
resources/non-numeric strings are preserved.

Benchmarks (Apple M1, -O2 -DNDEBUG release, median of 7 runs, n=10000
with ~20M total elements per case):

  array_sum, packed long                     42.24 ms ->  12.99 ms  3.25x
  array_product, packed small long (0..9)   144.63 ms ->  19.39 ms  7.46x
  array_product, packed range(1, 100)        82.94 ms ->  58.66 ms  1.41x
  array_sum, hash long                       41.95 ms ->  12.90 ms  3.25x
  array_product, hash small long (0..9)      69.90 ms ->  19.40 ms  3.60x
  packed/hash float, mixed IS_LONG/IS_DOUBLE ~            ~         ~1.00x

Tests cover the overflow transition from fast path to generic, and
the integration with array_column() together with the PHP 8.3
nested-array warning behavior.

* [ext/standard] Simplify array_sum/product iteration

* [ext/standard] Force inline array binop wrapper
2026-05-18 12:21:21 +01: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
Ben Ramsey 5164621436 license-update: ext/standard source headers
RFC: https://wiki.php.net/rfc/php_license_update
2026-04-11 21:20:54 -05:00
Gina Peter Banyard 9b48fe782d array_change_key_case(): Throw ValueError on invalid argument (#15883) 2026-04-10 11:23:28 +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