Skip to content

Commit d76ef13

Browse files
committed
Fix various hooked object iterator issues
Fixes phpGH-16185 Closes phpGH-16281
1 parent 3fcf8ca commit d76ef13

File tree

6 files changed

+209
-52
lines changed

6 files changed

+209
-52
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ PHP NEWS
3737
. Fixed bug GH-16188 (Assertion failure in Zend/zend_exceptions.c). (Arnaud)
3838
. Fixed bug GH-16233 (Observer segfault when calling user function in
3939
internal function via trampoline). (nielsdos)
40+
. Fixed bug GH-16185 (Various hooked object iterator issues). (ilutov)
4041

4142
- DOM:
4243
. Fixed bug GH-16039 (Segmentation fault (access null pointer) in

Zend/tests/property_hooks/dump.phpt

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,21 @@ function dump($test) {
5959
var_dump((array) $test);
6060
}
6161

62+
echo "dump(Test):\n";
6263
dump(new Test);
64+
65+
echo "\n\ndump(Child):\n";
6366
dump(new Child);
67+
68+
echo "\n\nChild::dumpTest():\n";
6469
(new Child)->dumpTest();
70+
71+
echo "\n\nChild::dumpChild():\n";
6572
(new Child)->dumpChild();
6673

6774
?>
6875
--EXPECTF--
76+
dump(Test):
6977
object(Test)#%d (4) {
7078
["addedHooks"]=>
7179
string(10) "addedHooks"
@@ -102,6 +110,9 @@ array(4) {
102110
["%0Test%0changed"]=>
103111
string(12) "changed Test"
104112
}
113+
114+
115+
dump(Child):
105116
object(Child)#%d (5) {
106117
["addedHooks"]=>
107118
string(10) "addedHooks"
@@ -124,11 +135,11 @@ array(3) {
124135
}
125136
\Child::__set_state(array(
126137
'addedHooks' => 'ADDEDHOOKS',
127-
'changed' => 'CHANGED CHILD',
128138
'virtual' => 'VIRTUAL',
129139
'backed' => 'BACKED',
130140
'private' => 'PRIVATE',
131-
'changed' => 'changed Child',
141+
'changed' => 'CHANGED TEST',
142+
'changed' => 'CHANGED CHILD',
132143
))
133144
{"addedHooks":"ADDEDHOOKS","virtual":"VIRTUAL","backed":"BACKED"}
134145
array(5) {
@@ -143,6 +154,9 @@ array(5) {
143154
["%0Child%0changed"]=>
144155
string(13) "changed Child"
145156
}
157+
158+
159+
Child::dumpTest():
146160
object(Child)#%d (5) {
147161
["addedHooks"]=>
148162
string(10) "addedHooks"
@@ -155,7 +169,7 @@ object(Child)#%d (5) {
155169
["changed":"Child":private]=>
156170
string(13) "changed Child"
157171
}
158-
array(4) {
172+
array(5) {
159173
["addedHooks"]=>
160174
string(10) "ADDEDHOOKS"
161175
["virtual"]=>
@@ -164,6 +178,8 @@ array(4) {
164178
string(6) "BACKED"
165179
["private"]=>
166180
string(7) "PRIVATE"
181+
["changed"]=>
182+
string(12) "CHANGED TEST"
167183
}
168184
array(5) {
169185
["addedHooks"]=>
@@ -179,11 +195,11 @@ array(5) {
179195
}
180196
\Child::__set_state(array(
181197
'addedHooks' => 'ADDEDHOOKS',
182-
'changed' => 'CHANGED CHILD',
183198
'virtual' => 'VIRTUAL',
184199
'backed' => 'BACKED',
185200
'private' => 'PRIVATE',
186-
'changed' => 'changed Child',
201+
'changed' => 'CHANGED TEST',
202+
'changed' => 'CHANGED CHILD',
187203
))
188204
{"addedHooks":"ADDEDHOOKS","virtual":"VIRTUAL","backed":"BACKED"}
189205
array(5) {
@@ -198,6 +214,9 @@ array(5) {
198214
["%0Child%0changed"]=>
199215
string(13) "changed Child"
200216
}
217+
218+
219+
Child::dumpChild():
201220
object(Child)#%d (5) {
202221
["addedHooks"]=>
203222
string(10) "addedHooks"
@@ -210,25 +229,23 @@ object(Child)#%d (5) {
210229
["changed":"Child":private]=>
211230
string(13) "changed Child"
212231
}
213-
array(5) {
232+
array(4) {
214233
["addedHooks"]=>
215234
string(10) "ADDEDHOOKS"
216-
["changed"]=>
217-
string(13) "CHANGED CHILD"
218235
["virtual"]=>
219236
string(7) "VIRTUAL"
220237
["backed"]=>
221238
string(6) "BACKED"
222239
["changed"]=>
223-
string(13) "changed Child"
240+
string(13) "CHANGED CHILD"
224241
}
225242
\Child::__set_state(array(
226243
'addedHooks' => 'ADDEDHOOKS',
227-
'changed' => 'CHANGED CHILD',
228244
'virtual' => 'VIRTUAL',
229245
'backed' => 'BACKED',
230246
'private' => 'PRIVATE',
231-
'changed' => 'changed Child',
247+
'changed' => 'CHANGED TEST',
248+
'changed' => 'CHANGED CHILD',
232249
))
233250
{"addedHooks":"ADDEDHOOKS","virtual":"VIRTUAL","backed":"BACKED"}
234251
array(5) {

Zend/tests/property_hooks/foreach.phpt

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,35 @@ testByVal(new ByVal);
8686
testByVal(new ByRef);
8787
testByRef(new ByRef);
8888

89+
class A {
90+
private $changed { get => 'A'; }
91+
protected $promoted { get => 'A'; }
92+
protected $protected { get => 'A'; }
93+
private $shadowed = 'A';
94+
95+
public function test() {
96+
foreach ($this as $k => $v) {
97+
var_dump($k, $v);
98+
}
99+
}
100+
}
101+
102+
#[AllowDynamicProperties]
103+
class B extends A {
104+
public $changed { get => 'B'; }
105+
public $promoted { get => 'B'; }
106+
}
107+
108+
$b = new B;
109+
$b->shadowed = 'Global';
110+
$b->test();
111+
89112
?>
90113
--EXPECTF--
114+
plain => plain
115+
ByRef::$virtualByRef::get
116+
virtualByRef => virtualByRef
117+
ByRef::$virtualByRef::set
91118
ByVal::$virtualByVal::get
92119
virtualByVal => virtualByVal
93120
ByVal::$virtualByVal::set
@@ -97,10 +124,6 @@ ByVal::$backed::set
97124
ByVal::$backedUninitialized::get
98125
backedUninitialized => backedUninitialized
99126
ByVal::$backedUninitialized::set
100-
plain => plain
101-
ByRef::$virtualByRef::get
102-
virtualByRef => virtualByRef
103-
ByRef::$virtualByRef::set
104127
dynamic => dynamic
105128
object(ByVal)#%d (6) {
106129
["plain"]=>
@@ -141,3 +164,11 @@ object(ByRef)#%d (3) {
141164
["dynamic"]=>
142165
string(7) "DYNAMIC"
143166
}
167+
string(7) "changed"
168+
string(1) "A"
169+
string(8) "promoted"
170+
string(1) "B"
171+
string(9) "protected"
172+
string(1) "A"
173+
string(8) "shadowed"
174+
string(1) "A"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-16185: Incorrect indexing into dynamic property array
3+
--FILE--
4+
<?php
5+
6+
class ByRef {
7+
private $_virtualByRef = 'virtualByRef';
8+
}
9+
10+
class ByVal extends ByRef {
11+
public $_virtualByRef {
12+
get => null;
13+
set { $this->dynamicProp = $value; }
14+
}
15+
}
16+
17+
$object = new ByVal;
18+
foreach ($object as $value) {
19+
var_dump($value);
20+
$object->_virtualByRef = $value;
21+
}
22+
23+
?>
24+
--EXPECTF--
25+
NULL
26+
27+
Deprecated: Creation of dynamic property ByVal::$dynamicProp is deprecated in %s on line %d
28+
NULL
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-16185: Hooked object iterator with readonly props
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public readonly int $prop;
8+
public $dummy { set {} }
9+
10+
public function init() {
11+
$this->prop = 1;
12+
}
13+
}
14+
15+
$c = new C;
16+
17+
// Okay, as foreach skips over uninitialized properties.
18+
foreach ($c as &$prop) {}
19+
20+
$c->init();
21+
22+
try {
23+
foreach ($c as &$prop) {}
24+
} catch (Error $e) {
25+
echo $e->getMessage(), "\n";
26+
}
27+
28+
?>
29+
--EXPECTF--
30+
Cannot acquire reference to readonly property C::$prop

0 commit comments

Comments
 (0)