Commit 10ff41ed120 for php

commit 10ff41ed12034bb8a27aa4b7854f71f7bc2e9a1f
Author: lazerg <lazerg2@gmail.com>
Date:   Sat Nov 7 06:01:44 2026 +0500

    Fix GH-25253: JIT reads parent of an unlinked class (#25259)

    zend_get_known_class() follows ce->parent for parent:: calls without
    checking ZEND_ACC_LINKED. For an unlinked class whose parent is declared in
    another file, this interprets parent_name as a class entry. A persisted
    string can pass the subsequent type and filename checks, causing
    zend_hash_find() to access invalid memory.

    Check ZEND_ACC_LINKED before reading ce->parent, as the optimizer already
    does. Add a regression test using opcache.interned_strings_buffer=0 to
    reproduce the shared-memory layout that triggers the crash.

    Co-authored-by: mlenarciak <39970740+mlenarciak@users.noreply.github.com>

    Closes #25259

diff --git a/NEWS b/NEWS
index 2ce93fa3739..8cc13383530 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,8 @@ PHP                                                                        NEWS
     SHM backend). (Lazizbek Ergashev)
   . Fixed bug GH-25269 (JIT: misaligned zval passed to
     ZEND_ADD_ARRAY_ELEMENT handler). (Jorg Sowa, ndossche)
+  . Fixed bug GH-25253 (JIT reads parent of an unlinked class).
+    (lazerg, mlenarciak)

 - SOAP:
   . Fixed bug GH-25267 (NULL dereference in to_xml_any() with integer key).
diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c
index 1490c43e5b7..ff016ad8ff1 100644
--- a/ext/opcache/jit/zend_jit.c
+++ b/ext/opcache/jit/zend_jit.c
@@ -592,7 +592,7 @@ static zend_class_entry* zend_get_known_class(const zend_op_array *op_array, con
 			ZEND_ASSERT((op.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT);
 			ce = op_array->scope;
 			if (ce) {
-				if (ce->parent) {
+				if ((ce->ce_flags & ZEND_ACC_LINKED) && ce->parent) {
 					ce = ce->parent;
 					if (ce->type == ZEND_INTERNAL_CLASS || ce->info.user.filename != op_array->filename) {
 						ce = NULL;
diff --git a/ext/opcache/tests/jit/gh25253.inc b/ext/opcache/tests/jit/gh25253.inc
new file mode 100644
index 00000000000..64db08b7513
--- /dev/null
+++ b/ext/opcache/tests/jit/gh25253.inc
@@ -0,0 +1,10 @@
+<?php
+
+class GH25253Child extends GH25253ParentClass {
+    public function m0() { return parent::m0(); }
+    public function m1() { return parent::m1(); }
+    public function m2() { return parent::m2(); }
+    public function m3() { return parent::m3(); }
+    public function m4() { return parent::m4(); }
+    public function m5() { return parent::m5(); }
+}
diff --git a/ext/opcache/tests/jit/gh25253.phpt b/ext/opcache/tests/jit/gh25253.phpt
new file mode 100644
index 00000000000..eb6c7c525ff
--- /dev/null
+++ b/ext/opcache/tests/jit/gh25253.phpt
@@ -0,0 +1,30 @@
+--TEST--
+GH-25253: JIT reads parent of an unlinked class
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.interned_strings_buffer=0
+opcache.jit=function
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+
+class GH25253ParentClass {
+    public function m0() { return 'm0'; }
+    public function m1() { return 'm1'; }
+    public function m2() { return 'm2'; }
+    public function m3() { return 'm3'; }
+    public function m4() { return 'm4'; }
+    public function m5() { return 'm5'; }
+}
+
+require __DIR__ . '/gh25253.inc';
+
+$c = new GH25253Child;
+echo $c->m0(), $c->m5(), "\n";
+
+?>
+--EXPECT--
+m0m5