diff options
author | Alex Dowad <alexinbeijing@gmail.com> | 2020-04-15 15:25:14 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-04-20 11:55:18 +0200 |
commit | 0d11d373574a7f831db6e3a7add60f2bbe28413f (patch) | |
tree | d9536cb0a68b089086a872bf8c8b462837d1079b | |
parent | 18ad38a7b21babeef16e25981c549e51da5388f1 (diff) | |
download | php-git-0d11d373574a7f831db6e3a7add60f2bbe28413f.tar.gz |
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.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | ext/spl/spl_array.c | 40 | ||||
-rw-r--r-- | ext/spl/tests/ArrayObject__serialize_saves_iterator_class.phpt | 15 | ||||
-rw-r--r-- | ext/spl/tests/array_025.phpt | 2 | ||||
-rw-r--r-- | ext/spl/tests/bug45826.phpt | 12 | ||||
-rw-r--r-- | ext/spl/tests/bug74669.phpt | 2 | ||||
-rw-r--r-- | ext/spl/tests/unserialize_errors.phpt | 27 | ||||
-rw-r--r-- | ext/standard/tests/serialize/bug45706.phpt | 4 |
8 files changed, 90 insertions, 14 deletions
@@ -28,6 +28,8 @@ PHP NEWS - SPL: . Fixed bug #69264 (__debugInfo() ignored while extending SPL classes). (cmb) + . Fixed bug #67369 (ArrayObject serialization drops the iterator class). + (Alex Dowad) - Standard: . Fixed bug #79468 (SIGSEGV when closing stream handle with a stream filter diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 3803055d30..5f70bfe7a0 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1840,6 +1840,14 @@ SPL_METHOD(Array, __serialize) ZVAL_ARR(&tmp, zend_std_get_properties(ZEND_THIS)); Z_TRY_ADDREF(tmp); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* iterator class */ + if (intern->ce_get_iterator == spl_ce_ArrayIterator) { + ZVAL_NULL(&tmp); + } else { + ZVAL_STR_COPY(&tmp, intern->ce_get_iterator->name); + } + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); } /* }}} */ @@ -1849,18 +1857,22 @@ SPL_METHOD(Array, __unserialize) { spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); HashTable *data; - zval *flags_zv, *storage_zv, *members_zv; + zval *flags_zv, *storage_zv, *members_zv, *iterator_class_zv; zend_long flags; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { return; } - flags_zv = zend_hash_index_find(data, 0); - storage_zv = zend_hash_index_find(data, 1); - members_zv = zend_hash_index_find(data, 2); + flags_zv = zend_hash_index_find(data, 0); + storage_zv = zend_hash_index_find(data, 1); + members_zv = zend_hash_index_find(data, 2); + iterator_class_zv = zend_hash_index_find(data, 3); + if (!flags_zv || !storage_zv || !members_zv || - Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY) { + Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY || + (iterator_class_zv && (Z_TYPE_P(iterator_class_zv) != IS_NULL && + Z_TYPE_P(iterator_class_zv) != IS_STRING))) { zend_throw_exception(spl_ce_UnexpectedValueException, "Incomplete or ill-typed serialization data", 0); return; @@ -1878,6 +1890,24 @@ SPL_METHOD(Array, __unserialize) } object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); + + if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) { + zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv)); + + if (!ce) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, + "Cannot deserialize ArrayObject with iterator class '%s'; no such class exists", + ZSTR_VAL(Z_STR_P(iterator_class_zv))); + return; + } else if (!instanceof_function(ce, spl_ce_Iterator)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, + "Cannot deserialize ArrayObject with iterator class '%s'; this class does not implement the Iterator interface", + ZSTR_VAL(Z_STR_P(iterator_class_zv))); + return; + } else { + intern->ce_get_iterator = ce; + } + } } /* }}} */ diff --git a/ext/spl/tests/ArrayObject__serialize_saves_iterator_class.phpt b/ext/spl/tests/ArrayObject__serialize_saves_iterator_class.phpt new file mode 100644 index 0000000000..9947311ea5 --- /dev/null +++ b/ext/spl/tests/ArrayObject__serialize_saves_iterator_class.phpt @@ -0,0 +1,15 @@ +--TEST-- +ArrayObject::__serialize saves any iterator class set by ::setIteratorClass +--FILE-- +<?php + +class MyArrayIterator extends ArrayIterator {} +$arrayObject = new ArrayObject(array(1, 2, 3)); +$arrayObject->setIteratorClass("MyArrayIterator"); +$serialized = serialize($arrayObject); +$backAgain = unserialize($serialized); +echo $backAgain->getIteratorClass(), "\n"; + +?> +--EXPECT-- +MyArrayIterator diff --git a/ext/spl/tests/array_025.phpt b/ext/spl/tests/array_025.phpt index 9a95de60eb..d64f8f04c1 100644 --- a/ext/spl/tests/array_025.phpt +++ b/ext/spl/tests/array_025.phpt @@ -24,7 +24,7 @@ ArrayObject Object ) ) -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:{}} +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;} ArrayObject Object ( [storage:ArrayObject:private] => ArrayObject Object diff --git a/ext/spl/tests/bug45826.phpt b/ext/spl/tests/bug45826.phpt index 8187b3a320..d4e6653306 100644 --- a/ext/spl/tests/bug45826.phpt +++ b/ext/spl/tests/bug45826.phpt @@ -16,7 +16,7 @@ $s2 = $o->serialize(); var_dump($s1); var_dump($s2); -$o1 =unserialize($s1); +$o1 = unserialize($s1); var_dump($o1[0] === $o1[1]); var_dump($o1[2] === $o1); @@ -69,8 +69,8 @@ var_dump($o2[2][2] === $o2[2]); --EXPECT-- bool(true) bool(true) -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:{}}" -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:{}" +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;}" +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:{}" bool(true) bool(true) bool(true) @@ -79,8 +79,8 @@ bool(true) #### Extending ArrayObject bool(true) bool(true) -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:{}}" -array(3) { +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;}" +array(4) { [0]=> int(0) [1]=> @@ -100,6 +100,8 @@ array(3) { [2]=> array(0) { } + [3]=> + NULL } bool(true) bool(true) diff --git a/ext/spl/tests/bug74669.phpt b/ext/spl/tests/bug74669.phpt index 264cd3b97a..6b4ceec65c 100644 --- a/ext/spl/tests/bug74669.phpt +++ b/ext/spl/tests/bug74669.phpt @@ -104,7 +104,7 @@ object(SelfArray)#9 (1) { ["foo"]=> string(3) "bar" } -string(71) "O:9:"SelfArray":3:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}}" +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;}" object(SelfArray)#9 (1) { ["foo"]=> string(3) "bar" diff --git a/ext/spl/tests/unserialize_errors.phpt b/ext/spl/tests/unserialize_errors.phpt index 237d0673c4..1138b5c8cd 100644 --- a/ext/spl/tests/unserialize_errors.phpt +++ b/ext/spl/tests/unserialize_errors.phpt @@ -6,6 +6,7 @@ Errors from __unserialize() with invalid data echo "ArrayObject:\n"; try { + // empty array unserialize('O:11:"ArrayObject":0:{}'); } catch (Exception $e) { echo $e->getMessage(), "\n"; @@ -29,6 +30,27 @@ try { echo $e->getMessage(), "\n"; } +try { + // iterator class name is not a string + unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;i:0;i:2;a:0:{}i:3;i:0;}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + 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";}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +class Existent {} + +try { + 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";}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + echo "ArrayIterator:\n"; try { @@ -114,12 +136,15 @@ try { } ?> ---EXPECTF-- +--EXPECT-- ArrayObject: Incomplete or ill-typed serialization data Incomplete or ill-typed serialization data Incomplete or ill-typed serialization data Passed variable is not an array or object +Incomplete or ill-typed serialization data +Cannot deserialize ArrayObject with iterator class 'NonExistent'; no such class exists +Cannot deserialize ArrayObject with iterator class 'Existent'; this class does not implement the Iterator interface ArrayIterator: Incomplete or ill-typed serialization data Incomplete or ill-typed serialization data diff --git a/ext/standard/tests/serialize/bug45706.phpt b/ext/standard/tests/serialize/bug45706.phpt index 12cadfe0fa..cc71dec4e6 100644 --- a/ext/standard/tests/serialize/bug45706.phpt +++ b/ext/standard/tests/serialize/bug45706.phpt @@ -15,7 +15,7 @@ var_dump($y); --EXPECTF-- array(2) { [0]=> - object(__PHP_Incomplete_Class)#3 (4) { + object(__PHP_Incomplete_Class)#3 (5) { ["__PHP_Incomplete_Class_Name"]=> string(4) "Bar1" ["0"]=> @@ -26,6 +26,8 @@ array(2) { ["2"]=> array(0) { } + ["3"]=> + NULL } [1]=> object(__PHP_Incomplete_Class)#4 (1) { |