Skip to content

Commit 0d11d37

Browse files
alexdowadnikic
authored andcommitted
Fix bug #67369 ArrayObject serializatino drops the iterator class
When ArrayObject is round-tripped through serialize() and unserialize(), it forgets any iterator class name which was set using ::setIteratorClass(). Fix that.
1 parent 18ad38a commit 0d11d37

File tree

8 files changed

+90
-14
lines changed

8 files changed

+90
-14
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ PHP NEWS
2828

2929
- SPL:
3030
. Fixed bug #69264 (__debugInfo() ignored while extending SPL classes). (cmb)
31+
. Fixed bug #67369 (ArrayObject serialization drops the iterator class).
32+
(Alex Dowad)
3133

3234
- Standard:
3335
. Fixed bug #79468 (SIGSEGV when closing stream handle with a stream filter

ext/spl/spl_array.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,14 @@ SPL_METHOD(Array, __serialize)
18401840
ZVAL_ARR(&tmp, zend_std_get_properties(ZEND_THIS));
18411841
Z_TRY_ADDREF(tmp);
18421842
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
1843+
1844+
/* iterator class */
1845+
if (intern->ce_get_iterator == spl_ce_ArrayIterator) {
1846+
ZVAL_NULL(&tmp);
1847+
} else {
1848+
ZVAL_STR_COPY(&tmp, intern->ce_get_iterator->name);
1849+
}
1850+
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
18431851
}
18441852
/* }}} */
18451853

@@ -1849,18 +1857,22 @@ SPL_METHOD(Array, __unserialize)
18491857
{
18501858
spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS);
18511859
HashTable *data;
1852-
zval *flags_zv, *storage_zv, *members_zv;
1860+
zval *flags_zv, *storage_zv, *members_zv, *iterator_class_zv;
18531861
zend_long flags;
18541862

18551863
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
18561864
return;
18571865
}
18581866

1859-
flags_zv = zend_hash_index_find(data, 0);
1860-
storage_zv = zend_hash_index_find(data, 1);
1861-
members_zv = zend_hash_index_find(data, 2);
1867+
flags_zv = zend_hash_index_find(data, 0);
1868+
storage_zv = zend_hash_index_find(data, 1);
1869+
members_zv = zend_hash_index_find(data, 2);
1870+
iterator_class_zv = zend_hash_index_find(data, 3);
1871+
18621872
if (!flags_zv || !storage_zv || !members_zv ||
1863-
Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY) {
1873+
Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY ||
1874+
(iterator_class_zv && (Z_TYPE_P(iterator_class_zv) != IS_NULL &&
1875+
Z_TYPE_P(iterator_class_zv) != IS_STRING))) {
18641876
zend_throw_exception(spl_ce_UnexpectedValueException,
18651877
"Incomplete or ill-typed serialization data", 0);
18661878
return;
@@ -1878,6 +1890,24 @@ SPL_METHOD(Array, __unserialize)
18781890
}
18791891

18801892
object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
1893+
1894+
if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) {
1895+
zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv));
1896+
1897+
if (!ce) {
1898+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1899+
"Cannot deserialize ArrayObject with iterator class '%s'; no such class exists",
1900+
ZSTR_VAL(Z_STR_P(iterator_class_zv)));
1901+
return;
1902+
} else if (!instanceof_function(ce, spl_ce_Iterator)) {
1903+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1904+
"Cannot deserialize ArrayObject with iterator class '%s'; this class does not implement the Iterator interface",
1905+
ZSTR_VAL(Z_STR_P(iterator_class_zv)));
1906+
return;
1907+
} else {
1908+
intern->ce_get_iterator = ce;
1909+
}
1910+
}
18811911
}
18821912
/* }}} */
18831913

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
ArrayObject::__serialize saves any iterator class set by ::setIteratorClass
3+
--FILE--
4+
<?php
5+
6+
class MyArrayIterator extends ArrayIterator {}
7+
$arrayObject = new ArrayObject(array(1, 2, 3));
8+
$arrayObject->setIteratorClass("MyArrayIterator");
9+
$serialized = serialize($arrayObject);
10+
$backAgain = unserialize($serialized);
11+
echo $backAgain->getIteratorClass(), "\n";
12+
13+
?>
14+
--EXPECT--
15+
MyArrayIterator

ext/spl/tests/array_025.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ ArrayObject Object
2424
)
2525

2626
)
27-
O:11:"ArrayObject":3:{i:0;i:0;i:1;O:11:"ArrayObject":3:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}}i:2;a:0:{}}
27+
O:11:"ArrayObject":4:{i:0;i:0;i:1;O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}i:3;N;}i:2;a:0:{}i:3;N;}
2828
ArrayObject Object
2929
(
3030
[storage:ArrayObject:private] => ArrayObject Object

ext/spl/tests/bug45826.phpt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ $s2 = $o->serialize();
1616
var_dump($s1);
1717
var_dump($s2);
1818

19-
$o1 =unserialize($s1);
19+
$o1 = unserialize($s1);
2020

2121
var_dump($o1[0] === $o1[1]);
2222
var_dump($o1[2] === $o1);
@@ -69,8 +69,8 @@ var_dump($o2[2][2] === $o2[2]);
6969
--EXPECT--
7070
bool(true)
7171
bool(true)
72-
string(90) "O:11:"ArrayObject":3:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}}"
73-
string(131) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;O:11:"ArrayObject":3:{i:0;i:0;i:1;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;}i:2;a:0:{}}};m:a:0:{}"
72+
string(96) "O:11:"ArrayObject":4:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}i:3;N;}"
73+
string(137) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;O:11:"ArrayObject":4:{i:0;i:0;i:1;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;}i:2;a:0:{}i:3;N;}};m:a:0:{}"
7474
bool(true)
7575
bool(true)
7676
bool(true)
@@ -79,8 +79,8 @@ bool(true)
7979
#### Extending ArrayObject
8080
bool(true)
8181
bool(true)
82-
string(91) "O:12:"ArrayObject2":3:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}}"
83-
array(3) {
82+
string(97) "O:12:"ArrayObject2":4:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}i:3;N;}"
83+
array(4) {
8484
[0]=>
8585
int(0)
8686
[1]=>
@@ -100,6 +100,8 @@ array(3) {
100100
[2]=>
101101
array(0) {
102102
}
103+
[3]=>
104+
NULL
103105
}
104106
bool(true)
105107
bool(true)

ext/spl/tests/bug74669.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ object(SelfArray)#9 (1) {
104104
["foo"]=>
105105
string(3) "bar"
106106
}
107-
string(71) "O:9:"SelfArray":3:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}}"
107+
string(77) "O:9:"SelfArray":4:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}i:3;N;}"
108108
object(SelfArray)#9 (1) {
109109
["foo"]=>
110110
string(3) "bar"

ext/spl/tests/unserialize_errors.phpt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Errors from __unserialize() with invalid data
66
echo "ArrayObject:\n";
77

88
try {
9+
// empty array
910
unserialize('O:11:"ArrayObject":0:{}');
1011
} catch (Exception $e) {
1112
echo $e->getMessage(), "\n";
@@ -29,6 +30,27 @@ try {
2930
echo $e->getMessage(), "\n";
3031
}
3132

33+
try {
34+
// iterator class name is not a string
35+
unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;i:0;i:2;a:0:{}i:3;i:0;}');
36+
} catch (Exception $e) {
37+
echo $e->getMessage(), "\n";
38+
}
39+
40+
try {
41+
unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}i:3;s:11:"NonExistent";}');
42+
} catch (Exception $e) {
43+
echo $e->getMessage(), "\n";
44+
}
45+
46+
class Existent {}
47+
48+
try {
49+
unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}i:3;s:8:"Existent";}');
50+
} catch (Exception $e) {
51+
echo $e->getMessage(), "\n";
52+
}
53+
3254
echo "ArrayIterator:\n";
3355

3456
try {
@@ -114,12 +136,15 @@ try {
114136
}
115137

116138
?>
117-
--EXPECTF--
139+
--EXPECT--
118140
ArrayObject:
119141
Incomplete or ill-typed serialization data
120142
Incomplete or ill-typed serialization data
121143
Incomplete or ill-typed serialization data
122144
Passed variable is not an array or object
145+
Incomplete or ill-typed serialization data
146+
Cannot deserialize ArrayObject with iterator class 'NonExistent'; no such class exists
147+
Cannot deserialize ArrayObject with iterator class 'Existent'; this class does not implement the Iterator interface
123148
ArrayIterator:
124149
Incomplete or ill-typed serialization data
125150
Incomplete or ill-typed serialization data

ext/standard/tests/serialize/bug45706.phpt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var_dump($y);
1515
--EXPECTF--
1616
array(2) {
1717
[0]=>
18-
object(__PHP_Incomplete_Class)#3 (4) {
18+
object(__PHP_Incomplete_Class)#3 (5) {
1919
["__PHP_Incomplete_Class_Name"]=>
2020
string(4) "Bar1"
2121
["0"]=>
@@ -26,6 +26,8 @@ array(2) {
2626
["2"]=>
2727
array(0) {
2828
}
29+
["3"]=>
30+
NULL
2931
}
3032
[1]=>
3133
object(__PHP_Incomplete_Class)#4 (1) {

0 commit comments

Comments
 (0)