From: Nikita Popov Date: Tue, 9 Apr 2019 12:57:06 +0000 (+0200) Subject: Fix bug #77866: Port Serializable SPL classes to use __unserialize() X-Git-Tag: php-7.4.0alpha1~570 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e2ea0f105c9c6c60b19f2584d72205e5b1fe11e8;p=php Fix bug #77866: Port Serializable SPL classes to use __unserialize() Payloads created using Serializable are still supported. --- diff --git a/UPGRADING b/UPGRADING index 7b460da4a0..33704bdb02 100644 --- a/UPGRADING +++ b/UPGRADING @@ -87,6 +87,11 @@ PHP 7.4 UPGRADE NOTES . SplPriorityQueue::setExtractFlags() will throw an exception if zero is passed. Previously this would generate a recoverable fatal error on the next extraction operation. + . ArrayObject, ArrayIterator, SplDoublyLinkedList and SplObjectStorage now + support the __serialize() + __unserialize() mechanism in addition to the + Serializable interface. This means that serialization payloads created on + older PHP versions can still be unserialized, but new payloads created by + PHP 7.4 will not be understood by older versions. - Standard: . The "o" serialization format has been removed. As it is never produced by diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index ab488726df..2806f93281 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1812,6 +1812,80 @@ outexcept: } /* }}} */ +/* {{{ proto array ArrayObject::__serialize() */ +SPL_METHOD(Array, __serialize) +{ + spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); + zval tmp; + + if (zend_parse_parameters_none_throw() == FAILURE) { + return; + } + + array_init(return_value); + + /* flags */ + ZVAL_LONG(&tmp, (intern->ar_flags & SPL_ARRAY_CLONE_MASK)); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* storage */ + if (intern->ar_flags & SPL_ARRAY_IS_SELF) { + ZVAL_NULL(&tmp); + } else { + ZVAL_COPY(&tmp, &intern->array); + } + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* members */ + ZVAL_ARR(&tmp, zend_std_get_properties(ZEND_THIS)); + Z_TRY_ADDREF(tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); +} +/* }}} */ + + +/* {{{ proto void ArrayObject::__unserialize(array data) */ +SPL_METHOD(Array, __unserialize) +{ + spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); + HashTable *data; + zval *flags_zv, *storage_zv, *members_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); + if (!flags_zv || !storage_zv || !members_zv || + Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY) { + zend_throw_exception(spl_ce_UnexpectedValueException, + "Incomplete or ill-typed serialization data", 0); + return; + } + + flags = Z_LVAL_P(flags_zv); + intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK; + intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK; + + if (flags & SPL_ARRAY_IS_SELF) { + zval_ptr_dtor(&intern->array); + ZVAL_UNDEF(&intern->array); + } else if (Z_TYPE_P(storage_zv) == IS_ARRAY) { + zval_ptr_dtor(&intern->array); + ZVAL_COPY_VALUE(&intern->array, storage_zv); + ZVAL_NULL(storage_zv); + SEPARATE_ARRAY(&intern->array); + } else { + spl_array_set_array(ZEND_THIS, intern, storage_zv, 0L, 1); + } + + object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); +} +/* }}} */ + /* {{{ arginfo and function table */ ZEND_BEGIN_ARG_INFO_EX(arginfo_array___construct, 0, 0, 0) ZEND_ARG_INFO(0, input) @@ -1884,6 +1958,8 @@ static const zend_function_entry spl_funcs_ArrayObject[] = { SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC) SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC) SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, __unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC) + SPL_ME(Array, __serialize, arginfo_array_void, ZEND_ACC_PUBLIC) /* ArrayObject specific */ SPL_ME(Array, getIterator, arginfo_array_void, ZEND_ACC_PUBLIC) SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC) @@ -1911,6 +1987,8 @@ static const zend_function_entry spl_funcs_ArrayIterator[] = { SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC) SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC) SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, __unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC) + SPL_ME(Array, __serialize, arginfo_array_void, ZEND_ACC_PUBLIC) /* ArrayIterator specific */ SPL_ME(Array, rewind, arginfo_array_void, ZEND_ACC_PUBLIC) SPL_ME(Array, current, arginfo_array_void, ZEND_ACC_PUBLIC) diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 2a274595f3..299cf70174 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -1220,6 +1220,67 @@ error: } /* }}} */ +/* {{{ proto array SplDoublyLinkedList::__serialize() */ +SPL_METHOD(SplDoublyLinkedList, __serialize) +{ + spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); + spl_ptr_llist_element *current = intern->llist->head; + zval tmp; + + if (zend_parse_parameters_none_throw() == FAILURE) { + return; + } + + array_init(return_value); + + /* flags */ + ZVAL_LONG(&tmp, intern->flags); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* elements */ + array_init_size(&tmp, intern->llist->count); + while (current) { + zend_hash_next_index_insert(Z_ARRVAL(tmp), ¤t->data); + current = current->next; + } + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* members */ + ZVAL_ARR(&tmp, zend_std_get_properties(ZEND_THIS)); + Z_TRY_ADDREF(tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); +} /* }}} */ + +/* {{{ proto void SplDoublyLinkedList::__unserialize(array serialized) */ +SPL_METHOD(SplDoublyLinkedList, __unserialize) { + spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); + HashTable *data; + zval *flags_zv, *storage_zv, *members_zv, *elem; + + 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); + if (!flags_zv || !storage_zv || !members_zv || + Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(storage_zv) != IS_ARRAY || + Z_TYPE_P(members_zv) != IS_ARRAY) { + zend_throw_exception(spl_ce_UnexpectedValueException, + "Incomplete or ill-typed serialization data", 0); + return; + } + + intern->flags = (int) Z_LVAL_P(flags_zv); + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), elem) { + spl_ptr_llist_push(intern->llist, elem); + } ZEND_HASH_FOREACH_END(); + + object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); +} /* }}} */ + /* {{{ proto void SplDoublyLinkedList::add(mixed index, mixed newval) Inserts a new entry before the specified $index consisting of $newval. */ SPL_METHOD(SplDoublyLinkedList, add) @@ -1374,6 +1435,8 @@ static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = { /* Serializable */ SPL_ME(SplDoublyLinkedList, unserialize, arginfo_dllist_serialized, ZEND_ACC_PUBLIC) SPL_ME(SplDoublyLinkedList, serialize, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, __unserialize, arginfo_dllist_serialized, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, __serialize, arginfo_dllist_void, ZEND_ACC_PUBLIC) PHP_FE_END }; /* }}} */ diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 8b170afaee..3810195193 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -868,6 +868,78 @@ outexcept: } /* }}} */ +/* {{{ proto auto SplObjectStorage::__serialize() */ +SPL_METHOD(SplObjectStorage, __serialize) +{ + spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); + spl_SplObjectStorageElement *elem; + zval tmp; + + if (zend_parse_parameters_none_throw() == FAILURE) { + return; + } + + array_init(return_value); + + /* storage */ + array_init_size(&tmp, 2 * zend_hash_num_elements(&intern->storage)); + ZEND_HASH_FOREACH_PTR(&intern->storage, elem) { + Z_TRY_ADDREF(elem->obj); + zend_hash_next_index_insert(Z_ARRVAL(tmp), &elem->obj); + Z_TRY_ADDREF(elem->inf); + zend_hash_next_index_insert(Z_ARRVAL(tmp), &elem->inf); + } ZEND_HASH_FOREACH_END(); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* members */ + ZVAL_ARR(&tmp, zend_std_get_properties(ZEND_THIS)); + Z_TRY_ADDREF(tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); +} /* }}} */ + +/* {{{ proto void SplObjectStorage::__unserialize(array serialized) */ +SPL_METHOD(SplObjectStorage, __unserialize) +{ + spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); + HashTable *data; + zval *storage_zv, *members_zv, *key, *val; + + if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { + return; + } + + storage_zv = zend_hash_index_find(data, 0); + members_zv = zend_hash_index_find(data, 1); + if (!storage_zv || !members_zv || + Z_TYPE_P(storage_zv) != IS_ARRAY || Z_TYPE_P(members_zv) != IS_ARRAY) { + zend_throw_exception(spl_ce_UnexpectedValueException, + "Incomplete or ill-typed serialization data", 0); + return; + } + + if (zend_hash_num_elements(Z_ARRVAL_P(storage_zv)) % 2 != 0) { + zend_throw_exception(spl_ce_UnexpectedValueException, "Odd number of elements", 0); + return; + } + + key = NULL; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), val) { + if (key) { + if (Z_TYPE_P(key) != IS_OBJECT) { + zend_throw_exception(spl_ce_UnexpectedValueException, "Non-object key", 0); + return; + } + + spl_object_storage_attach(intern, ZEND_THIS, key, val); + key = NULL; + } else { + key = val; + } + } ZEND_HASH_FOREACH_END(); + + object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); +} + ZEND_BEGIN_ARG_INFO(arginfo_Object, 0) ZEND_ARG_INFO(0, object) ZEND_END_ARG_INFO(); @@ -917,6 +989,8 @@ static const zend_function_entry spl_funcs_SplObjectStorage[] = { /* Serializable */ SPL_ME(SplObjectStorage, unserialize, arginfo_Serialized, 0) SPL_ME(SplObjectStorage, serialize, arginfo_splobject_void,0) + SPL_ME(SplObjectStorage, __unserialize, arginfo_Serialized, 0) + SPL_ME(SplObjectStorage, __serialize, arginfo_splobject_void,0) /* ArrayAccess */ SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0) SPL_MA(SplObjectStorage, offsetSet, SplObjectStorage, attach, arginfo_attach, 0) diff --git a/ext/spl/tests/SplDoublyLinkedList_serialization.phpt b/ext/spl/tests/SplDoublyLinkedList_serialization.phpt index 7ab7d78174..d04e0cbe72 100644 --- a/ext/spl/tests/SplDoublyLinkedList_serialization.phpt +++ b/ext/spl/tests/SplDoublyLinkedList_serialization.phpt @@ -29,7 +29,7 @@ object(SplQueue)#%d (2) { string(1) "b" } } -string(42) "C:8:"SplQueue":22:{i:4;:s:1:"a";:s:1:"b";}" +string(71) "O:8:"SplQueue":3:{i:0;i:4;i:1;a:2:{i:0;s:1:"a";i:1;s:1:"b";}i:2;a:0:{}}" object(SplQueue)#%d (2) { ["flags":"SplDoublyLinkedList":private]=> int(4) @@ -52,7 +52,7 @@ object(SplStack)#%d (2) { string(1) "b" } } -string(42) "C:8:"SplStack":22:{i:6;:s:1:"a";:s:1:"b";}" +string(71) "O:8:"SplStack":3:{i:0;i:6;i:1;a:2:{i:0;s:1:"a";i:1;s:1:"b";}i:2;a:0:{}}" object(SplStack)#%d (2) { ["flags":"SplDoublyLinkedList":private]=> int(6) diff --git a/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt index daf415049c..c75662c66e 100644 --- a/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt +++ b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt @@ -18,7 +18,7 @@ echo $s."\n"; $so1 = unserialize($s); var_dump($so1); --EXPECTF-- -C:16:"SplObjectStorage":76:{x:i:2;O:8:"stdClass":1:{s:1:"a";O:8:"stdClass":0:{}},i:1;;r:4;,i:2;;m:a:0:{}} +O:16:"SplObjectStorage":2:{i:0;a:4:{i:0;O:8:"stdClass":1:{s:1:"a";O:8:"stdClass":0:{}}i:1;i:1;i:2;r:4;i:3;i:2;}i:1;a:0:{}} object(SplObjectStorage)#4 (1) { ["storage":"SplObjectStorage":private]=> array(2) { diff --git a/ext/spl/tests/array_025.phpt b/ext/spl/tests/array_025.phpt index 35893ea1ea..9a95de60eb 100644 --- a/ext/spl/tests/array_025.phpt +++ b/ext/spl/tests/array_025.phpt @@ -24,7 +24,7 @@ ArrayObject Object ) ) -C:11:"ArrayObject":76:{x:i:0;C:11:"ArrayObject":37:{x:i:0;a:2:{i:0;i:1;i:1;i:2;};m:a:0:{}};m:a:0:{}} +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:{}} ArrayObject Object ( [storage:ArrayObject:private] => ArrayObject Object diff --git a/ext/spl/tests/bug45826.phpt b/ext/spl/tests/bug45826.phpt index 7993bfaa95..8187b3a320 100644 --- a/ext/spl/tests/bug45826.phpt +++ b/ext/spl/tests/bug45826.phpt @@ -31,12 +31,12 @@ var_dump($o2[2][2] === $o2[2]); echo "#### Extending ArrayObject\n"; unset($o,$x,$s1,$s2,$o1,$o2); class ArrayObject2 extends ArrayObject { - public function serialize() { - return parent::serialize(); + public function __serialize() { + return parent::__serialize(); } - public function unserialize($s) { - return parent::unserialize($s); + public function __unserialize($s) { + return parent::__unserialize($s); } } @@ -50,17 +50,17 @@ var_dump($o[0] === $o[1]); var_dump($o[2] === $o); $s1 = serialize($o); -$s2 = $o->serialize(); +$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); $o2 = new ArrayObject2(); -$o2->unserialize($s2); +$o2->__unserialize($s2); var_dump($o2[0] === $o2[1]); var_dump($o2[2] !== $o2); @@ -69,8 +69,8 @@ var_dump($o2[2][2] === $o2[2]); --EXPECT-- bool(true) bool(true) -string(84) "C:11:"ArrayObject":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}" -string(125) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:11:"ArrayObject":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}" +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:{}" bool(true) bool(true) bool(true) @@ -79,8 +79,28 @@ bool(true) #### Extending ArrayObject bool(true) bool(true) -string(85) "C:12:"ArrayObject2":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}" -string(126) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:12:"ArrayObject2":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}" +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) { + [0]=> + int(0) + [1]=> + array(3) { + [0]=> + object(stdClass)#8 (0) { + } + [1]=> + object(stdClass)#8 (0) { + } + [2]=> + object(ArrayObject2)#5 (1) { + ["storage":"ArrayObject":private]=> + *RECURSION* + } + } + [2]=> + array(0) { + } +} bool(true) bool(true) bool(true) diff --git a/ext/spl/tests/bug49263.phpt b/ext/spl/tests/bug49263.phpt index a2e2e0b396..4d9e8e1d60 100644 --- a/ext/spl/tests/bug49263.phpt +++ b/ext/spl/tests/bug49263.phpt @@ -17,7 +17,7 @@ var_dump(unserialize($ss)); ?> ===DONE=== --EXPECTF-- -C:16:"SplObjectStorage":113:{x:i:2;O:8:"stdClass":0:{},a:2:{s:4:"prev";i:2;s:4:"next";O:8:"stdClass":0:{}};r:6;,a:1:{s:4:"prev";r:3;};m:a:0:{}} +O:16:"SplObjectStorage":2:{i:0;a:4:{i:0;O:8:"stdClass":0:{}i:1;a:2:{s:4:"prev";i:2;s:4:"next";O:8:"stdClass":0:{}}i:2;r:6;i:3;a:1:{s:4:"prev";r:3;}}i:1;a:0:{}} object(SplObjectStorage)#2 (1) { ["storage":"SplObjectStorage":private]=> array(2) { diff --git a/ext/spl/tests/bug74669.phpt b/ext/spl/tests/bug74669.phpt index 5e4fcd023b..264cd3b97a 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(62) "C:9:"SelfArray":41:{x:i:16777216;m:a:1:{s:3:"foo";s: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";}}" object(SelfArray)#9 (1) { ["foo"]=> string(3) "bar" diff --git a/ext/spl/tests/unserialize_errors.phpt b/ext/spl/tests/unserialize_errors.phpt new file mode 100644 index 0000000000..237d0673c4 --- /dev/null +++ b/ext/spl/tests/unserialize_errors.phpt @@ -0,0 +1,138 @@ +--TEST-- +Errors from __unserialize() with invalid data +--FILE-- +getMessage(), "\n"; +} + +try { + unserialize('O:11:"ArrayObject":3:{i:0;b:1;i:1;a:0:{}i:2;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:11:"ArrayObject":3:{i:0;i:0;i:1;a:0:{}i:2;i:0;}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:11:"ArrayObject":3:{i:0;i:0;i:1;i:0;i:2;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +echo "ArrayIterator:\n"; + +try { + unserialize('O:13:"ArrayIterator":0:{}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:13:"ArrayIterator":3:{i:0;b:1;i:1;a:0:{}i:2;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:13:"ArrayIterator":3:{i:0;i:0;i:1;a:0:{}i:2;i:0;}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:13:"ArrayIterator":3:{i:0;i:0;i:1;i:0;i:2;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +echo "SplDoublyLinkedList:\n"; + +try { + unserialize('O:19:"SplDoublyLinkedList":0:{}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:19:"SplDoublyLinkedList":3:{i:0;b:1;i:1;a:0:{}i:2;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:19:"SplDoublyLinkedList":3:{i:0;i:0;i:1;a:0:{}i:2;i:0;}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:19:"SplDoublyLinkedList":3:{i:0;i:0;i:1;i:0;i:2;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +echo "SplObjectStorage:\n"; + +try { + unserialize('O:16:"SplObjectStorage":0:{}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:16:"SplObjectStorage":2:{i:0;i:0;i:1;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:16:"SplObjectStorage":2:{i:0;a:0:{}i:1;i:1;}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:16:"SplObjectStorage":2:{i:0;a:1:{i:0;i:0;}i:1;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + unserialize('O:16:"SplObjectStorage":2:{i:0;a:2:{i:0;i:0;i:1;i:0;}i:1;a:0:{}}'); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +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 +ArrayIterator: +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 +SplDoublyLinkedList: +Incomplete or ill-typed serialization data +Incomplete or ill-typed serialization data +Incomplete or ill-typed serialization data +Incomplete or ill-typed serialization data +SplObjectStorage: +Incomplete or ill-typed serialization data +Incomplete or ill-typed serialization data +Incomplete or ill-typed serialization data +Odd number of elements +Non-object key diff --git a/ext/standard/tests/serialize/bug45706.phpt b/ext/standard/tests/serialize/bug45706.phpt index 218cdcca2d..12cadfe0fa 100644 --- a/ext/standard/tests/serialize/bug45706.phpt +++ b/ext/standard/tests/serialize/bug45706.phpt @@ -13,15 +13,22 @@ $s = str_replace("Foo", "Bar", $s); $y = unserialize($s); var_dump($y); --EXPECTF-- -Warning: Class __PHP_Incomplete_Class has no unserializer in %sbug45706.php on line %d array(2) { [0]=> - object(__PHP_Incomplete_Class)#%d (1) { + object(__PHP_Incomplete_Class)#3 (4) { ["__PHP_Incomplete_Class_Name"]=> string(4) "Bar1" + ["0"]=> + int(0) + ["1"]=> + array(0) { + } + ["2"]=> + array(0) { + } } [1]=> - object(__PHP_Incomplete_Class)#%d (1) { + object(__PHP_Incomplete_Class)#4 (1) { ["__PHP_Incomplete_Class_Name"]=> string(4) "Bar2" } diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 588aa43d8b..1dadbe5a29 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -646,7 +646,7 @@ static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, zend_ if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements, NULL)) { ZVAL_DEREF(rval); GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED); - zval_ptr_dtor(&ary); + zval_ptr_dtor(&ary); return 0; }