Skip to content

Commit ee0dcce

Browse files
committed
Don't overload get_properties for ArrayObject
Instead overload get_properties_for for a few specific cases such as array casts. This resolves the issue where ArrayObject get_properties may violate engine invariants in some cases.
1 parent d2e7506 commit ee0dcce

File tree

6 files changed

+105
-56
lines changed

6 files changed

+105
-56
lines changed

ext/reflection/tests/bug61388.phpt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ print_r($reflObj->getProperties(ReflectionProperty::IS_PUBLIC));
1414
--EXPECT--
1515
Array
1616
(
17-
[0] => ReflectionProperty Object
18-
(
19-
[name] => test
20-
[class] => ArrayObject
21-
)
22-
2317
)
2418
Array
2519
(

ext/spl/spl_array.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -807,18 +807,40 @@ SPL_METHOD(Array, getArrayCopy)
807807
RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
808808
} /* }}} */
809809

810-
static HashTable *spl_array_get_properties(zval *object) /* {{{ */
810+
static HashTable *spl_array_get_properties_for(zval *object, zend_prop_purpose purpose) /* {{{ */
811811
{
812812
spl_array_object *intern = Z_SPLARRAY_P(object);
813+
HashTable *ht;
814+
zend_bool dup;
813815

814816
if (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) {
815-
if (!intern->std.properties) {
816-
rebuild_object_properties(&intern->std);
817-
}
818-
return intern->std.properties;
817+
return zend_std_get_properties_for(object, purpose);
818+
}
819+
820+
/* We are supposed to be the only owner of the internal hashtable.
821+
* The "dup" flag decides whether this is a "long-term" use where
822+
* we need to duplicate, or a "temporary" one, where we can expect
823+
* that no operations on the ArrayObject will be performed in the
824+
* meantime. */
825+
switch (purpose) {
826+
case ZEND_PROP_PURPOSE_ARRAY_CAST:
827+
dup = 1;
828+
break;
829+
case ZEND_PROP_PURPOSE_VAR_EXPORT:
830+
case ZEND_PROP_PURPOSE_JSON:
831+
dup = 0;
832+
break;
833+
default:
834+
return zend_std_get_properties_for(object, purpose);
819835
}
820836

821-
return spl_array_get_hash_table(intern);
837+
ht = spl_array_get_hash_table(intern);
838+
if (dup) {
839+
ht = zend_array_dup(ht);
840+
} else {
841+
GC_ADDREF(ht);
842+
}
843+
return ht;
822844
} /* }}} */
823845

824846
static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp) /* {{{ */
@@ -2013,7 +2035,7 @@ PHP_MINIT_FUNCTION(spl_array)
20132035
spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
20142036
spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
20152037

2016-
spl_handler_ArrayObject.get_properties = spl_array_get_properties;
2038+
spl_handler_ArrayObject.get_properties_for = spl_array_get_properties_for;
20172039
spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
20182040
spl_handler_ArrayObject.get_gc = spl_array_get_gc;
20192041
spl_handler_ArrayObject.read_property = spl_array_read_property;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
get_object_vars() on ArrayObject works on the properties of the ArrayObject itself
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public $test;
8+
public $test2;
9+
}
10+
11+
class AO extends ArrayObject {
12+
private $test;
13+
14+
public function getObjectVars() {
15+
return get_object_vars($this);
16+
}
17+
}
18+
19+
$ao = new AO(new Test);
20+
var_dump(get_object_vars($ao));
21+
var_dump($ao->getObjectVars());
22+
23+
?>
24+
--EXPECT--
25+
array(0) {
26+
}
27+
array(1) {
28+
["test"]=>
29+
NULL
30+
}

ext/spl/tests/array_017.phpt

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,17 @@ array(3) {
139139
["Flags"]=>
140140
int(0)
141141
["OVars"]=>
142-
array(3) {
143-
[0]=>
144-
int(1)
145-
["a"]=>
146-
int(25)
142+
array(5) {
147143
["pub1"]=>
148-
int(42)
144+
int(1)
145+
["pro1"]=>
146+
int(2)
147+
["pri1"]=>
148+
int(3)
149+
["imp1"]=>
150+
int(4)
151+
["dyn1"]=>
152+
int(5)
149153
}
150154
["$this"]=>
151155
object(ArrayObjectEx)#%d (6) {
@@ -178,13 +182,17 @@ array(3) {
178182
["Flags"]=>
179183
int(0)
180184
["OVars"]=>
181-
array(3) {
182-
[0]=>
185+
array(5) {
186+
["pub2"]=>
183187
int(1)
184-
["a"]=>
185-
int(25)
186-
["pub1"]=>
187-
int(42)
188+
["pro2"]=>
189+
int(2)
190+
["pri2"]=>
191+
int(3)
192+
["imp2"]=>
193+
int(4)
194+
["dyn2"]=>
195+
int(5)
188196
}
189197
["$this"]=>
190198
object(ArrayIteratorEx)#%d (6) {
@@ -242,13 +250,17 @@ array(3) {
242250
["Flags"]=>
243251
int(0)
244252
["OVars"]=>
245-
array(3) {
246-
[0]=>
253+
array(5) {
254+
["pub2"]=>
247255
int(1)
248-
["a"]=>
249-
int(25)
250-
["pub1"]=>
251-
int(42)
256+
["pro2"]=>
257+
int(2)
258+
["pri2"]=>
259+
int(3)
260+
["imp2"]=>
261+
int(4)
262+
["dyn2"]=>
263+
int(5)
252264
}
253265
["$this"]=>
254266
object(ArrayIteratorEx)#%d (6) {
@@ -541,14 +553,16 @@ array(3) {
541553
["Flags"]=>
542554
int(0)
543555
["OVars"]=>
544-
array(4) {
545-
["pub1"]=>
556+
array(5) {
557+
["pub2"]=>
546558
int(1)
547-
["pro1"]=>
559+
["pro2"]=>
548560
int(2)
549-
["imp1"]=>
561+
["pri2"]=>
562+
int(3)
563+
["imp2"]=>
550564
int(4)
551-
["dyn1"]=>
565+
["dyn2"]=>
552566
int(5)
553567
}
554568
["$this"]=>
@@ -598,14 +612,16 @@ array(3) {
598612
["Flags"]=>
599613
int(0)
600614
["OVars"]=>
601-
array(4) {
602-
["pub1"]=>
615+
array(5) {
616+
["pub2"]=>
603617
int(1)
604-
["pro1"]=>
618+
["pro2"]=>
605619
int(2)
606-
["imp1"]=>
620+
["pri2"]=>
621+
int(3)
622+
["imp2"]=>
607623
int(4)
608-
["dyn1"]=>
624+
["dyn2"]=>
609625
int(5)
610626
}
611627
["$this"]=>

ext/spl/tests/bug61347.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var_dump(isset($b['no_exists'])); //false
1212
var_dump(empty($b['b'])); //true
1313
var_dump(empty($b[37])); //true
1414

15-
var_dump(array_key_exists('b', $b)); //true
15+
var_dump(array_key_exists('b', $b)); //false
1616
var_dump($b['b']);
1717

1818
$a = array('b' => '', 37 => false);
@@ -31,7 +31,7 @@ bool(false)
3131
bool(false)
3232
bool(true)
3333
bool(true)
34-
bool(true)
34+
bool(false)
3535
NULL
3636
bool(true)
3737
bool(true)

tests/classes/arrayobject_001.phpt

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)