[php-src] master: Merge branch 'PHP-8.5' into PHP-8.6
| From: | Arnaud Le Blanc | Date: | Fri, 02 Oct 2026 14:24:32 +0000 |
| Subject: | [php-src] master: Merge branch 'PHP-8.5' into PHP-8.6 | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-141881@lists.php.net to get a copy of this message | ||
Author: Arnaud Le Blanc (arnaud-lb)
Date: 2026-10-02T16:24:08+02:00
Commit: https://github.com/php/php-src/commit/38b2036e6f70de1000cd9177c113f7e5195eae47
Raw diff: https://github.com/php/php-src/commit/38b2036e6f70de1000cd9177c113f7e5195eae47.diff
Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5:
Fix GH-24063: SCCP merges 0.0 and -0.0 into a single constant (#24064)
Changed paths:
A ext/opcache/tests/opt/gh24063.phpt
M NEWS
M Zend/Optimizer/sccp.c
Diff:
diff --git a/NEWS b/NEWS
index 191a241cb246..f9ce88ceec19 100644
--- a/NEWS
+++ b/NEWS
@@ -61,6 +61,8 @@ PHP NEWS
child's shadowing public property). (Ilia Alshanetsky)
. Fix multiple incorrect DCE due to unsound escape analysis. (ndossche,
arnaud-lb)
+ . Fixed bug GH-24063 (OPcache optimizer folds
$cond ? -0.0 : 0.0 into a
+ single -0.0 constant). (lazerg)
- OpenSSL:
. Fixed stream_socket_enable_crypto() leaving the socket non-blocking
diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c
index 72ba6d98888e..01ba8e6ba676 100644
--- a/Zend/Optimizer/sccp.c
+++ b/Zend/Optimizer/sccp.c
@@ -1951,6 +1951,28 @@ static void sccp_mark_feasible_successors(
scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
}
+/* Unlike zend_is_identical(), this does not treat 0.0 and -0.0 as the same value.
+ * Returns int to be usable as compare_func_t. */
+static int sccp_values_differ(const void *p1, const void *p2)
+{
+ const zval *a = p1;
+ const zval *b = p2;
+
+ if (Z_TYPE_P(a) != Z_TYPE_P(b)) {
+ return 1;
+ }
+ if (Z_TYPE_P(a) == IS_DOUBLE) {
+ return memcmp(&Z_DVAL_P(a), &Z_DVAL_P(b), sizeof(double)) != 0;
+ }
+ if (Z_TYPE_P(a) == IS_ARRAY) {
+ return Z_ARRVAL_P(a) != Z_ARRVAL_P(b)
+ && zend_hash_compare(Z_ARRVAL_P(a), Z_ARRVAL_P(b), sccp_values_differ, 1) != 0;
+ }
+ ZEND_ASSERT(IS_PARTIAL_ARRAY(a) || IS_PARTIAL_OBJECT(a)
+ || ((1 << Z_TYPE_P(a)) &
(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_BOOL|MAY_BE_LONG|MAY_BE_STRING)));
+ return !zend_is_identical(a, b);
+}
+
static void join_hash_tables(HashTable *ret, const HashTable *ht1, const HashTable *ht2)
{
zend_ulong index;
@@ -1963,7 +1985,7 @@ static void join_hash_tables(HashTable *ret, const HashTable *ht1, const
HashTab
} else {
val2 = zend_hash_index_find(ht2, index);
}
- if (val2 && zend_is_identical(val1, val2)) {
+ if (val2 && !sccp_values_differ(val1, val2)) {
if (key) {
val1 = zend_hash_add_new(ret, key, val1);
} else {
@@ -2031,7 +2053,7 @@ static void join_phi_values(zval *a, const zval *b, bool escape) {
zval_ptr_dtor_nogc(a);
MAKE_BOT(a);
}
- } else if (!zend_is_identical(a, b)) {
+ } else if (sccp_values_differ(a, b)) {
if (join_partial_arrays(a, b) == FAILURE) {
zval_ptr_dtor_nogc(a);
MAKE_BOT(a);
diff --git a/ext/opcache/tests/opt/gh24063.phpt b/ext/opcache/tests/opt/gh24063.phpt
new file mode 100644
index 000000000000..36f3ddbdca13
--- /dev/null
+++ b/ext/opcache/tests/opt/gh24063.phpt
@@ -0,0 +1,46 @@
+--TEST--
+GH-24063 (SCCP merges 0.0 and -0.0 into a single constant)
+--EXTENSIONS--
+opcache
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--FILE--
+<?php
+
+function scalar(float $n): float
+{
+ $r = $n < 0 ? -0.0 : 0.0;
+ return $r;
+}
+
+function arr(float $n): array
+{
+ $r = $n < 0 ? [-0.0] : [0.0];
+ return $r;
+}
+
+function partial(float $n, $x): float
+{
+ $a = ['x' => $x];
+ if ($n < 0) {
+ $a['k'] = -0.0;
+ } else {
+ $a['k'] = 0.0;
+ }
+ return $a['k'];
+}
+
+var_dump(scalar(1.0), scalar(-1.0));
+var_dump(arr(1.0)[0], arr(-1.0)[0]);
+var_dump(partial(1.0, 1), partial(-1.0, 1));
+
+?>
+--EXPECT--
+float(0)
+float(-0)
+float(0)
+float(-0)
+float(0)
+float(-0)