From f4e822cd90bcb1ff34fcb4913907d85ffd035400 Mon Sep 17 00:00:00 2001 From: lazerg Date: Mon, 2 Nov 2026 19:01:04 +0500 Subject: [PATCH 1/2] Fix GH-25149: Leak of class constant type names in uncached classes --- Zend/zend_opcode.c | 3 +++ ext/opcache/tests/gh25149.phpt | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 ext/opcache/tests/gh25149.phpt diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 317f68b486bb..4edd1fbc7cb9 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -421,6 +421,9 @@ ZEND_API void destroy_zend_class(zval *zv) zend_hash_release(c->attributes); } } + if (c->ce == ce) { + zend_type_release(c->type, /* persistent */ 0); + } } ZEND_HASH_FOREACH_END(); } zend_hash_destroy(&ce->constants_table); diff --git a/ext/opcache/tests/gh25149.phpt b/ext/opcache/tests/gh25149.phpt new file mode 100644 index 000000000000..d280a795d9b9 --- /dev/null +++ b/ext/opcache/tests/gh25149.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-25149 (Memory leak of class constant type names in classes not cached by opcache) +--EXTENSIONS-- +opcache +--INI-- +opcache.enable_cli=1 +--FILE-- + +--EXPECT-- +NULL +NULL From 18249a1c170c6294eaa0588896b40b60278770a9 Mon Sep 17 00:00:00 2001 From: lazerg Date: Mon, 2 Nov 2026 20:03:39 +0500 Subject: [PATCH 2/2] Deep copy class constant types for trait and lazy loaded copies --- Zend/zend_inheritance.c | 2 ++ ext/opcache/tests/gh25149.phpt | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 4d73dd003a31..a4c759add64b 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2847,6 +2847,7 @@ static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_ent constant->ce = ce; Z_TRY_ADDREF(constant->value); + zend_type_copy_ctor(&constant->type, /* use_arena */ true, /* persistent */ false); constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL; if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) { GC_ADDREF(constant->attributes); @@ -3489,6 +3490,7 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) Z_PTR(p->val) = new_c; memcpy(new_c, c, sizeof(zend_class_constant)); new_c->ce = ce; + zend_type_copy_ctor(&new_c->type, /* use_arena */ true, /* persistent */ false); } } diff --git a/ext/opcache/tests/gh25149.phpt b/ext/opcache/tests/gh25149.phpt index d280a795d9b9..657dc193d1a6 100644 --- a/ext/opcache/tests/gh25149.phpt +++ b/ext/opcache/tests/gh25149.phpt @@ -11,7 +11,19 @@ eval('class A { const ?GH25149_B C = null; }'); eval('class D { const GH25149_E|GH25149_F|null G = null; }'); var_dump(A::C, D::G); +eval('trait T { const ?GH25149_H I = null; const GH25149_J|GH25149_K|null L = null; }'); +eval('class M { use T; }'); +var_dump(M::I, M::L); + +eval('class N {}'); +class O extends N { const ?GH25149_P Q = null; const GH25149_R|GH25149_S|null U = null; } +var_dump(O::Q, O::U); + ?> --EXPECT-- NULL NULL +NULL +NULL +NULL +NULL