Skip to content

Commit 7b46b55

Browse files
committed
Fix phpGH-21770: Infinite recursion in property hook getter in opcache preloaded trait
preload_fix_trait_op_array rewrites the clone op_array from its original after optimization, preserving function_name, scope, fn_flags, prototype, and static_variables. For trait-cloned property hooks, it also needs to preserve prop_info: zend_do_traits_property_binding set it to the using class's property, but the reset pointed it back at the trait's property. That mismatch caused zend_is_in_hook to miss the self-access check inside the hook, recursing into the getter/setter instead of reading or writing the backing store. Closes phpGH-21770
1 parent afded3d commit 7b46b55

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

ext/opcache/ZendAccelerator.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4290,12 +4290,14 @@ static void preload_fix_trait_op_array(zend_op_array *op_array)
42904290
uint32_t fn_flags = op_array->fn_flags;
42914291
zend_function *prototype = op_array->prototype;
42924292
HashTable *ht = op_array->static_variables;
4293+
zend_property_info *prop_info = op_array->prop_info;
42934294
*op_array = *orig_op_array;
42944295
op_array->function_name = function_name;
42954296
op_array->scope = scope;
42964297
op_array->fn_flags = fn_flags;
42974298
op_array->prototype = prototype;
42984299
op_array->static_variables = ht;
4300+
op_array->prop_info = prop_info;
42994301
}
43004302

43014303
static void preload_fix_trait_methods(zend_class_entry *ce)

ext/opcache/tests/gh21770.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-21770 (Infinite recursion in property hook getter in opcache preloaded trait)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
opcache.preload={PWD}/preload_gh21770.inc
8+
--EXTENSIONS--
9+
opcache
10+
--SKIPIF--
11+
<?php
12+
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
13+
?>
14+
--FILE--
15+
<?php
16+
$b = new B();
17+
echo $b->a, "\n";
18+
19+
$c = new C();
20+
$c->x = 42;
21+
var_dump($c->x);
22+
?>
23+
--EXPECT--
24+
a
25+
int(42)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
trait A {
3+
public ?string $a = 'a' {
4+
get => $this->a;
5+
}
6+
}
7+
8+
trait X {
9+
public int $x = 0 {
10+
set(int $value) => $this->x = $value;
11+
}
12+
}
13+
14+
class B {
15+
use A;
16+
}
17+
18+
class C {
19+
use X;
20+
}

0 commit comments

Comments
 (0)