Skip to content

Commit e0c69dd

Browse files
committed
Fix accidentally inherited default value in overridden virtual properties
Discovered when working on phpGH-17376.
1 parent 7a55116 commit e0c69dd

File tree

6 files changed

+67
-4
lines changed

6 files changed

+67
-4
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ PHP NEWS
55
- Core:
66
. Fixed property hook backing value access in multi-level inheritance.
77
(ilutov)
8+
. Fixed accidentally inherited default value in overridden virtual properties.
9+
(ilutov)
810

911
27 Feb 2025, PHP 8.4.5
1012

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Property default values are not inherited
3+
--FILE--
4+
<?php
5+
6+
class P {
7+
public $a = 1;
8+
public int $b = 1;
9+
public $c = 1;
10+
public int $d = 1;
11+
}
12+
13+
class C extends P {
14+
public $a { get => parent::$a::get(); }
15+
public int $b { get => parent::$b::get(); }
16+
public $c = 2 { get => parent::$c::get(); }
17+
public int $d = 2 { get => parent::$d::get(); }
18+
}
19+
20+
class GC extends C {
21+
public $a { get => parent::$a::get(); }
22+
public int $b { get => parent::$b::get(); }
23+
public $c { get => parent::$c::get(); }
24+
public int $d { get => parent::$d::get(); }
25+
}
26+
27+
function test(P $p) {
28+
var_dump($p->a);
29+
try {
30+
var_dump($p->b);
31+
} catch (Error $e) {
32+
echo $e->getMessage(), "\n";
33+
}
34+
var_dump($p->c);
35+
try {
36+
var_dump($p->d);
37+
} catch (Error $e) {
38+
echo $e->getMessage(), "\n";
39+
}
40+
}
41+
42+
test(new C);
43+
test(new GC);
44+
45+
?>
46+
--EXPECT--
47+
NULL
48+
Typed property C::$b must not be accessed before initialization
49+
int(2)
50+
int(2)
51+
NULL
52+
Typed property GC::$b must not be accessed before initialization
53+
NULL
54+
Typed property GC::$d must not be accessed before initialization

Zend/tests/property_hooks/dump.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class Test {
3434
}
3535

3636
class Child extends Test {
37-
public $addedHooks {
37+
public $addedHooks = 'addedHooks' {
3838
get { return strtoupper(parent::$addedHooks::get()); }
3939
}
4040
private $changed = 'changed Child' {

Zend/tests/property_hooks/generator_hook_002.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class A {
88
}
99

1010
class B extends A {
11-
public $prop {
11+
public $prop = 42 {
1212
get {
1313
yield parent::$prop::get() + 1;
1414
yield parent::$prop::get() + 2;

Zend/tests/property_hooks/parent_get_plain.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class P {
88
}
99

1010
class C extends P {
11-
public $prop {
11+
public $prop = 42 {
1212
get => parent::$prop::get();
1313
}
1414
}

Zend/zend_inheritance.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -1478,14 +1478,21 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
14781478
zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ZSTR_VAL(ce->name), ZSTR_VAL(key), zend_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name), (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
14791479
}
14801480
if (!(child_info->flags & ZEND_ACC_STATIC) && !(parent_info->flags & ZEND_ACC_VIRTUAL)) {
1481+
int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
14811482
if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1482-
int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
14831483
int child_num = OBJ_PROP_TO_NUM(child_info->offset);
14841484

14851485
/* Don't keep default properties in GC (they may be freed by opcache) */
14861486
zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
14871487
ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
14881488
ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1489+
} else {
1490+
/* Default value was removed in child, remove it from parent too. */
1491+
if (ZEND_TYPE_IS_SET(child_info->type)) {
1492+
ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1493+
} else {
1494+
ZVAL_NULL(&ce->default_properties_table[parent_num]);
1495+
}
14891496
}
14901497

14911498
child_info->offset = parent_info->offset;

0 commit comments

Comments
 (0)