From 5009142bc766ff44b8223ef1697e887f85b9061f Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 2 May 2024 21:11:29 +0200 Subject: [PATCH] Fix persisting of inherited class constants Class constants are inherited to user classes without cloning. Thus, internal class constants should not be persisted at all. Simply keep pointing to the internal class constant. Fixes GH-14109 --- ext/opcache/zend_persist.c | 7 ++++++- ext/opcache/zend_persist_calc.c | 6 ++++++ ext/zend_test/tests/gh14109.phpt | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 ext/zend_test/tests/gh14109.phpt diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 7513f71db3401..7cc22f9669196 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -806,12 +806,17 @@ static zend_property_info *zend_persist_property_info(zend_property_info *prop) static void zend_persist_class_constant(zval *zv) { - zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv)); + zend_class_constant *orig_c = Z_PTR_P(zv); + zend_class_constant *c = zend_shared_alloc_get_xlat_entry(orig_c); zend_class_entry *ce; if (c) { Z_PTR_P(zv) = c; return; + } else if (((orig_c->ce->ce_flags & ZEND_ACC_IMMUTABLE) && !(Z_CONSTANT_FLAGS(orig_c->value) & CONST_OWNED)) + || orig_c->ce->type == ZEND_INTERNAL_CLASS) { + /* Class constant comes from a different file in shm or internal class, keep existing pointer. */ + return; } else if (!ZCG(current_persistent_script)->corrupted && zend_accel_in_shm(Z_PTR_P(zv))) { return; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index c4c5c5fa3ba5f..881f3954c04f3 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -26,6 +26,7 @@ #include "zend_shared_alloc.h" #include "zend_operators.h" #include "zend_attributes.h" +#include "zend_constants.h" #define ADD_DUP_SIZE(m,s) ZCG(current_persistent_script)->size += zend_shared_memdup_size((void*)m, s) #define ADD_SIZE(m) ZCG(current_persistent_script)->size += ZEND_ALIGNED_SIZE(m) @@ -386,6 +387,11 @@ static void zend_persist_class_constant_calc(zval *zv) zend_class_constant *c = Z_PTR_P(zv); if (!zend_shared_alloc_get_xlat_entry(c)) { + if (((c->ce->ce_flags & ZEND_ACC_IMMUTABLE) && !(Z_CONSTANT_FLAGS(c->value) & CONST_OWNED)) + || c->ce->type == ZEND_INTERNAL_CLASS) { + /* Class constant comes from a different file in shm or internal class, keep existing pointer. */ + return; + } if (!ZCG(current_persistent_script)->corrupted && zend_accel_in_shm(Z_PTR_P(zv))) { return; diff --git a/ext/zend_test/tests/gh14109.phpt b/ext/zend_test/tests/gh14109.phpt new file mode 100644 index 0000000000000..be8c5a75a7bc2 --- /dev/null +++ b/ext/zend_test/tests/gh14109.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-14109: User class extending internal class with attributes +--EXTENSIONS-- +zend_test +--FILE-- +getAttributes() as $attribute) { + var_dump($attribute->newInstance()); +} +?> +--EXPECTF-- +object(ZendTestRepeatableAttribute)#%d (0) { +} +object(ZendTestRepeatableAttribute)#%d (0) { +}