Skip to content

Commit b30448f

Browse files
committed
Fix observing inherited internal functions
Fixes GH-9871
1 parent 79d4fda commit b30448f

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

Zend/zend_inheritance.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,21 +3135,18 @@ static zend_always_inline bool register_early_bound_ce(zval *delayed_early_bindi
31353135
if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
31363136
if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
31373137
Z_CE_P(delayed_early_binding) = ce;
3138-
zend_observer_class_linked_notify(ce, lcname);
31393138
return true;
31403139
}
31413140
} else {
31423141
/* If preloading is used, don't replace the existing bucket, add a new one. */
31433142
if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3144-
zend_observer_class_linked_notify(ce, lcname);
31453143
return true;
31463144
}
31473145
}
31483146
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
31493147
return false;
31503148
}
31513149
if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3152-
zend_observer_class_linked_notify(ce, lcname);
31533150
return true;
31543151
}
31553152
return false;
@@ -3170,6 +3167,7 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
31703167
if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
31713168
return NULL;
31723169
}
3170+
zend_observer_class_linked_notify(ret, lcname);
31733171
return ret;
31743172
}
31753173
} else {
@@ -3244,6 +3242,7 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
32443242
if (ZSTR_HAS_CE_CACHE(ce->name)) {
32453243
ZSTR_SET_CE_CACHE(ce->name, ce);
32463244
}
3245+
zend_observer_class_linked_notify(ce, lcname);
32473246

32483247
return ce;
32493248
}

ext/opcache/zend_persist.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,11 @@ static void zend_persist_class_method(zval *zv, zend_class_entry *ce)
723723
}
724724
}
725725
}
726-
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
726+
// Real dynamically created internal functions like enum methods must have their own run_time_cache pointer. They're always on the same scope as their defining class.
727+
// However, copies - as caused by inheritance of internal methods - must retain the original run_time_cache pointer, shared with the source function.
728+
if (!op_array->scope || op_array->scope == ce) {
729+
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
730+
}
727731
}
728732
}
729733
return;

ext/zend_test/tests/gh9871.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Test observing inherited internal functions
3+
--EXTENSIONS--
4+
zend_test
5+
--INI--
6+
opcache.enable_cli=1
7+
zend_test.observer.enabled=1
8+
zend_test.observer.observe_all=1
9+
zend_test.observer.show_return_value=1
10+
--FILE--
11+
<?php
12+
13+
class MyReflectionProperty extends ReflectionProperty {
14+
}
15+
16+
class A {
17+
protected $protected = 'a';
18+
}
19+
20+
$property = new MyReflectionProperty('A', 'protected');
21+
$property->setAccessible(true);
22+
23+
?>
24+
--EXPECT--
25+
<!-- init '/Users/bob.weinand/php-src/ext/zend_test/tests/gh9871.php' -->
26+
<file '/Users/bob.weinand/php-src/ext/zend_test/tests/gh9871.php'>
27+
<!-- init ReflectionProperty::__construct() -->
28+
<ReflectionProperty::__construct>
29+
</ReflectionProperty::__construct:NULL>
30+
<!-- init ReflectionProperty::setAccessible() -->
31+
<ReflectionProperty::setAccessible>
32+
</ReflectionProperty::setAccessible:NULL>
33+
</file '/Users/bob.weinand/php-src/ext/zend_test/tests/gh9871.php'>

0 commit comments

Comments
 (0)