Skip to content

Commit 1522e6b

Browse files
committed
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
1 parent 8c8287a commit 1522e6b

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

ext/opcache/zend_persist.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,26 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
923923
ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, p) {
924924
ZEND_ASSERT(p->key != NULL);
925925
zend_accel_store_interned_string(p->key);
926-
zend_persist_class_constant(&p->val);
926+
927+
zend_class_constant *c = Z_PTR(p->val);
928+
if (c->ce == orig_ce || (Z_CONSTANT_FLAGS(c->value) & CONST_OWNED)) {
929+
zend_persist_class_constant(&p->val);
930+
} else {
931+
zend_class_constant *new_c = zend_shared_alloc_get_xlat_entry(c);
932+
if (new_c) {
933+
Z_PTR(p->val) = new_c;
934+
} else {
935+
#ifndef ZEND_WIN32
936+
/* Internal class constant, keep the pointer to the old one. */
937+
ZEND_ASSERT(c->ce->type == ZEND_INTERNAL_CLASS);
938+
#else
939+
/* Windows must not persist linked classes with internal parents. We must not
940+
* point to internal structures in shm on Windows, because they might live in
941+
* different places for each process. */
942+
ZEND_UNREACHABLE();
943+
#endif
944+
}
945+
}
927946
} ZEND_HASH_FOREACH_END();
928947
HT_FLAGS(&ce->constants_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
929948

ext/opcache/zend_persist_calc.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "zend_shared_alloc.h"
2727
#include "zend_operators.h"
2828
#include "zend_attributes.h"
29+
#include "zend_constants.h"
2930

3031
#define ADD_DUP_SIZE(m,s) ZCG(current_persistent_script)->size += zend_shared_memdup_size((void*)m, s)
3132
#define ADD_SIZE(m) ZCG(current_persistent_script)->size += ZEND_ALIGNED_SIZE(m)
@@ -451,7 +452,11 @@ void zend_persist_class_entry_calc(zend_class_entry *ce)
451452
ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, p) {
452453
ZEND_ASSERT(p->key != NULL);
453454
ADD_INTERNED_STRING(p->key);
454-
zend_persist_class_constant_calc(&p->val);
455+
456+
zend_class_constant *c = Z_PTR(p->val);
457+
if (c->ce == ce || (Z_CONSTANT_FLAGS(c->value) & CONST_OWNED)) {
458+
zend_persist_class_constant_calc(&p->val);
459+
}
455460
} ZEND_HASH_FOREACH_END();
456461

457462
zend_hash_persist_calc(&ce->properties_info);

ext/zend_test/tests/gh14109.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-14109: User class extending internal class with attributes
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
class Test extends ZendAttributeTest {}
8+
foreach ((new ReflectionClassConstant(Test::class, 'TEST_CONST'))->getAttributes() as $attribute) {
9+
var_dump($attribute->newInstance());
10+
}
11+
?>
12+
--EXPECTF--
13+
object(ZendTestRepeatableAttribute)#%d (0) {
14+
}
15+
object(ZendTestRepeatableAttribute)#%d (0) {
16+
}

0 commit comments

Comments
 (0)