Commit 7c94b351dbb for php.net
commit 7c94b351dbb44f51cf210540f49cddae64fe2037
Author: Lazizbek Ergashev <lazerg2@gmail.com>
Date: Fri Sep 11 03:06:11 2026 +0500
Fix GH-23644: crash on a constant-vs-constant empty array comparison
Co-authored-by: ndossche <7771979+ndossche@users.noreply.github.com>
diff --git a/NEWS b/NEWS
index 8c4131fd642..47e627b104b 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fixed incorrect internal pointer and foreach iterator positions when
compacting arrays with holes. (Weilin Du)
+ . Fixed bug GH-23644 (Optimizer leaves a constant-vs-constant comparison
+ unfolded, crashing the VM in zval_undefined_cv). (ndossche)
- DOM:
. Fixed use-after-free when re-constructing a DOMXPath whose php:function
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 90a666ab71e..27b0e44218f 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -10105,7 +10105,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info
ZEND_VM_SMART_BRANCH(result, 0);
}
-ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op2_type == IS_CONST && (Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(RT_CONSTANT(op, op->op2))) == 0), ZEND_IS_IDENTICAL_EMPTY_ARRAY, TMPVARCV, CONST, SPEC(SMART_BRANCH,COMMUTATIVE))
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op2_type == IS_CONST && (Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(RT_CONSTANT(op, op->op2))) == 0), ZEND_IS_IDENTICAL_EMPTY_ARRAY, TMPVARCV, CONST, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1;
@@ -10118,7 +10118,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op2_type == IS_CONST && (Z_TYPE
ZEND_VM_SMART_BRANCH(result, 0);
}
-ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL, op->op2_type == IS_CONST && (Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(RT_CONSTANT(op, op->op2))) == 0), ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY, TMPVARCV, CONST, SPEC(SMART_BRANCH,COMMUTATIVE))
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL, op->op2_type == IS_CONST && (Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(RT_CONSTANT(op, op->op2))) == 0), ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY, TMPVARCV, CONST, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1;
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 9a98804f25c..2ba4011cf2b 100644
Binary files a/Zend/zend_vm_execute.h and b/Zend/zend_vm_execute.h differ
diff --git a/ext/opcache/tests/opt/gh23644.phpt b/ext/opcache/tests/opt/gh23644.phpt
new file mode 100644
index 00000000000..3094722c32a
--- /dev/null
+++ b/ext/opcache/tests/opt/gh23644.phpt
@@ -0,0 +1,28 @@
+--TEST--
+GH-23644 (Crash on a constant-vs-constant empty array comparison)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--EXTENSIONS--
+opcache
+--CREDITS--
+LTSCommerce
+--FILE--
+<?php
+function f($x) {
+ if (null !== $x || [] !== $x) { return 1; }
+ return 2;
+}
+
+function g($x) {
+ if ($x === null) { return $x === [] ? 'eq' : 'ne'; }
+ return 'other';
+}
+
+var_dump(f(null));
+var_dump(g(null));
+?>
+--EXPECT--
+int(1)
+string(2) "ne"