Commit c8e5c27b3da for php
commit c8e5c27b3da15e50ba7695d272f3520fe45255a5
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date: Sat Oct 3 11:29:26 2026 +0200
Fix type inference of ADD_ARRAY_UNPACK with integer keys
This causes a crash with the JIT for the provided test, because JIT
will only emit the hash case even though the array is gonna be packed.
Closes GH-24093.
diff --git a/NEWS b/NEWS
index df64bebbbc8..12b88a7e8e6 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,7 @@ PHP NEWS
. Fixed bug GH-17626 (JIT corrupts an opline handler when blacklisting a
root trace at the opcache.jit_max_root_traces limit, causing spurious
"Too few arguments" errors and crashes). (RV7PR)
+ . Fix type inference of ADD_ARRAY_UNPACK with integer keys. (ndossche)
- SOAP:
. Fixed use of uninitialized func in do_request() on OOM bailout.
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index f0d8d873977..66369a15482 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -3454,7 +3454,11 @@ static zend_always_inline zend_result _zend_update_type_info(
case ZEND_ADD_ARRAY_UNPACK:
tmp = ssa_var_info[ssa_op->result_use].type;
ZEND_ASSERT(tmp & MAY_BE_ARRAY);
- tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
+ if (t1 & MAY_BE_ARRAY_KEY_LONG) {
+ /* Integer keys are appended without copying the hash/packed layout of the source array. */
+ tmp |= MAY_BE_HASH_ONLY(tmp) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
+ }
+ tmp |= t1 & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
if (t1 & MAY_BE_OBJECT) {
tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
}
diff --git a/ext/opcache/tests/jit/add_array_unpack_packed.phpt b/ext/opcache/tests/jit/add_array_unpack_packed.phpt
new file mode 100644
index 00000000000..f0b6b9a33ce
--- /dev/null
+++ b/ext/opcache/tests/jit/add_array_unpack_packed.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT: unpacking a hash array with integer keys produces a packed array
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.jit_buffer_size=64M
+opcache.jit=1205
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+function f($c) {
+ $b = $c ? [-5 => 1, -6 => 2, -7 => 3] : [-7 => 2];
+ $a = [...$b];
+ foreach ($a as $k => $v) {
+ echo "$k => $v\n";
+ }
+}
+f(true);
+?>
+--EXPECT--
+0 => 1
+1 => 2
+2 => 3