From 2a4c9f32a8354023072c9b5f18c2288dce8900c4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 3 Apr 2020 09:02:07 +0200 Subject: [PATCH 1/7] Fix #69264: __debugInfo() ignored while extending SPL classes We actually implement `::__debugInfo()` and drop the `get_debug_info()` handlers of all relevant SPL classes. This is cleaner and gives more flexibility regarding overriding the functionality in descendant classes. --- ext/spl/spl_array.c | 22 +++++++++- ext/spl/spl_directory.c | 16 +++++-- ext/spl/spl_dllist.c | 15 +++++-- ext/spl/spl_heap.c | 40 +++++++++-------- ext/spl/spl_observer.c | 17 ++++++-- ext/spl/tests/bug69264.phpt | 86 +++++++++++++++++++++++++++++++++++++ 6 files changed, 166 insertions(+), 30 deletions(-) create mode 100644 ext/spl/tests/bug69264.phpt diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 90861b49c68f0..151b84e8be237 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -822,7 +822,7 @@ static HashTable *spl_array_get_properties_for(zval *object, zend_prop_purpose p return ht; } /* }}} */ -static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp) /* {{{ */ +static zend_always_inline HashTable* spl_array_get_debug_info(zval *obj, int *is_temp) /* {{{ */ { zval *storage; zend_string *zname; @@ -1883,6 +1883,24 @@ SPL_METHOD(Array, __unserialize) } /* }}} */ +/* {{{ proto void Array::__debugInfo() */ +SPL_METHOD(Array, __debugInfo) +{ + HashTable *ht; + int is_temp; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + ht = spl_array_get_debug_info(getThis(), &is_temp); + if (!is_temp && !(GC_FLAGS(ht) & GC_IMMUTABLE)) { + GC_ADDREF(ht); + } + + RETURN_ARR(ht); +} /* }}} */ + /* {{{ arginfo and function table */ ZEND_BEGIN_ARG_INFO_EX(arginfo_array___construct, 0, 0, 0) ZEND_ARG_INFO(0, input) @@ -1957,6 +1975,7 @@ static const zend_function_entry spl_funcs_ArrayObject[] = { 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) + SPL_ME(Array, __debugInfo, 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) @@ -2023,7 +2042,6 @@ PHP_MINIT_FUNCTION(spl_array) spl_handler_ArrayObject.count_elements = spl_array_object_count_elements; spl_handler_ArrayObject.get_properties_for = spl_array_get_properties_for; - spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info; spl_handler_ArrayObject.get_gc = spl_array_get_gc; spl_handler_ArrayObject.read_property = spl_array_read_property; spl_handler_ArrayObject.write_property = spl_array_write_property; diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index d7995bd7fac7f..cb3ae755b673d 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -598,7 +598,7 @@ static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, s } /* }}} */ -static HashTable *spl_filesystem_object_get_debug_info(zval *object, int *is_temp) /* {{{ */ +static zend_always_inline HashTable *spl_filesystem_object_get_debug_info(zval *object) /* {{{ */ { spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(object); zval tmp; @@ -608,8 +608,6 @@ static HashTable *spl_filesystem_object_get_debug_info(zval *object, int *is_tem size_t path_len; char stmp[2]; - *is_temp = 1; - if (!intern->std.properties) { rebuild_object_properties(&intern->std); } @@ -1421,6 +1419,16 @@ SPL_METHOD(SplFileInfo, getPathInfo) } /* }}} */ +/* {{{ proto void SplFileInfo::__debugInfo() */ +SPL_METHOD(SplFileInfo, __debugInfo) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ARR(spl_filesystem_object_get_debug_info(getThis())); +} /* }}} */ + /* {{{ proto SplFileInfo::_bad_state_ex(void) */ SPL_METHOD(SplFileInfo, _bad_state_ex) { @@ -1947,6 +1955,7 @@ static const zend_function_entry spl_SplFileInfo_functions[] = { SPL_ME(SplFileInfo, openFile, arginfo_info_openFile, ZEND_ACC_PUBLIC) SPL_ME(SplFileInfo, setFileClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) SPL_ME(SplFileInfo, setInfoClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, __debugInfo, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) SPL_ME(SplFileInfo, _bad_state_ex, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) SPL_MA(SplFileInfo, __toString, SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) PHP_FE_END @@ -3143,7 +3152,6 @@ PHP_MINIT_FUNCTION(spl_directory) spl_filesystem_object_handlers.offset = XtOffsetOf(spl_filesystem_object, std); spl_filesystem_object_handlers.clone_obj = spl_filesystem_object_clone; spl_filesystem_object_handlers.cast_object = spl_filesystem_object_cast; - spl_filesystem_object_handlers.get_debug_info = spl_filesystem_object_get_debug_info; spl_filesystem_object_handlers.dtor_obj = spl_filesystem_object_destroy_object; spl_filesystem_object_handlers.free_obj = spl_filesystem_object_free_storage; spl_ce_SplFileInfo->serialize = zend_class_serialize_deny; diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index a0eb06a97aa49..648a9ce4c4f61 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -492,7 +492,7 @@ static int spl_dllist_object_count_elements(zval *object, zend_long *count) /* { } /* }}} */ -static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp) /* {{{{ */ +static zend_always_inline HashTable* spl_dllist_object_get_debug_info(zval *obj) /* {{{{ */ { spl_dllist_object *intern = Z_SPLDLLIST_P(obj); spl_ptr_llist_element *current = intern->llist->head, *next; @@ -500,7 +500,6 @@ static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp) /* { zend_string *pnstr; int i = 0; HashTable *debug_info; - *is_temp = 1; if (!intern->std.properties) { rebuild_object_properties(&intern->std); @@ -1344,6 +1343,16 @@ SPL_METHOD(SplDoublyLinkedList, add) } } /* }}} */ +/* {{{ proto void SplDoublyLinkedList::__debugInfo() */ +SPL_METHOD(SplDoublyLinkedList, __debugInfo) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ARR(spl_dllist_object_get_debug_info(getThis())); +} /* }}} */ + /* {{{ iterator handler table */ static const zend_object_iterator_funcs spl_dllist_it_funcs = { spl_dllist_it_dtor, @@ -1425,6 +1434,7 @@ static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = { SPL_ME(SplDoublyLinkedList, isEmpty, arginfo_dllist_void, ZEND_ACC_PUBLIC) SPL_ME(SplDoublyLinkedList, setIteratorMode, arginfo_dllist_setiteratormode, ZEND_ACC_PUBLIC) SPL_ME(SplDoublyLinkedList, getIteratorMode, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, __debugInfo, arginfo_dllist_void, ZEND_ACC_PUBLIC) /* Countable */ SPL_ME(SplDoublyLinkedList, count, arginfo_dllist_void, ZEND_ACC_PUBLIC) /* ArrayAccess */ @@ -1459,7 +1469,6 @@ PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */ spl_handler_SplDoublyLinkedList.offset = XtOffsetOf(spl_dllist_object, std); spl_handler_SplDoublyLinkedList.clone_obj = spl_dllist_object_clone; spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements; - spl_handler_SplDoublyLinkedList.get_debug_info = spl_dllist_object_get_debug_info; spl_handler_SplDoublyLinkedList.get_gc = spl_dllist_object_get_gc; spl_handler_SplDoublyLinkedList.dtor_obj = zend_objects_destroy_object; spl_handler_SplDoublyLinkedList.free_obj = spl_dllist_object_free_storage; diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 8191c2901d6d7..948ef0ce66a5d 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -501,15 +501,13 @@ static int spl_heap_object_count_elements(zval *object, zend_long *count) /* {{{ } /* }}} */ -static HashTable* spl_heap_object_get_debug_info_helper(zend_class_entry *ce, zval *obj, int *is_temp) { /* {{{ */ +static zend_always_inline HashTable* spl_heap_object_get_debug_info(zend_class_entry *ce, zval *obj) { /* {{{ */ spl_heap_object *intern = Z_SPLHEAP_P(obj); zval tmp, heap_array; zend_string *pnstr; HashTable *debug_info; int i; - *is_temp = 1; - if (!intern->std.properties) { rebuild_object_properties(&intern->std); } @@ -571,18 +569,6 @@ static HashTable *spl_pqueue_object_get_gc(zval *obj, zval **gc_data, int *gc_da } /* }}} */ -static HashTable* spl_heap_object_get_debug_info(zval *obj, int *is_temp) /* {{{ */ -{ - return spl_heap_object_get_debug_info_helper(spl_ce_SplHeap, obj, is_temp); -} -/* }}} */ - -static HashTable* spl_pqueue_object_get_debug_info(zval *obj, int *is_temp) /* {{{ */ -{ - return spl_heap_object_get_debug_info_helper(spl_ce_SplPriorityQueue, obj, is_temp); -} -/* }}} */ - /* {{{ proto int SplHeap::count() Return the number of elements in the heap. */ SPL_METHOD(SplHeap, count) @@ -1065,6 +1051,26 @@ SPL_METHOD(SplPriorityQueue, current) } /* }}} */ +/* {{{ proto void SplHeap::__debugInfo() */ +SPL_METHOD(SplHeap, __debugInfo) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ARR(spl_heap_object_get_debug_info(spl_ce_SplHeap, getThis())); +} /* }}} */ + +/* {{{ proto void SplPriorityQueue::__debugInfo() */ +SPL_METHOD(SplPriorityQueue, __debugInfo) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ARR(spl_heap_object_get_debug_info(spl_ce_SplPriorityQueue, getThis())); +} /* }}} */ + /* iterator handler table */ static const zend_object_iterator_funcs spl_heap_it_funcs = { spl_heap_it_dtor, @@ -1183,6 +1189,7 @@ static const zend_function_entry spl_funcs_SplPriorityQueue[] = { SPL_ME(SplHeap, valid, arginfo_splheap_void, ZEND_ACC_PUBLIC) SPL_ME(SplHeap, recoverFromCorruption, arginfo_splheap_void, ZEND_ACC_PUBLIC) SPL_ME(SplHeap, isCorrupted, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplPriorityQueue, __debugInfo, arginfo_splheap_void, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -1199,6 +1206,7 @@ static const zend_function_entry spl_funcs_SplHeap[] = { SPL_ME(SplHeap, valid, arginfo_splheap_void, ZEND_ACC_PUBLIC) SPL_ME(SplHeap, recoverFromCorruption, arginfo_splheap_void, ZEND_ACC_PUBLIC) SPL_ME(SplHeap, isCorrupted, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, __debugInfo, arginfo_splheap_void, ZEND_ACC_PUBLIC) ZEND_FENTRY(compare, NULL, NULL, ZEND_ACC_PROTECTED|ZEND_ACC_ABSTRACT) PHP_FE_END }; @@ -1212,7 +1220,6 @@ PHP_MINIT_FUNCTION(spl_heap) /* {{{ */ spl_handler_SplHeap.offset = XtOffsetOf(spl_heap_object, std); spl_handler_SplHeap.clone_obj = spl_heap_object_clone; spl_handler_SplHeap.count_elements = spl_heap_object_count_elements; - spl_handler_SplHeap.get_debug_info = spl_heap_object_get_debug_info; spl_handler_SplHeap.get_gc = spl_heap_object_get_gc; spl_handler_SplHeap.dtor_obj = zend_objects_destroy_object; spl_handler_SplHeap.free_obj = spl_heap_object_free_storage; @@ -1234,7 +1241,6 @@ PHP_MINIT_FUNCTION(spl_heap) /* {{{ */ spl_handler_SplPriorityQueue.offset = XtOffsetOf(spl_heap_object, std); spl_handler_SplPriorityQueue.clone_obj = spl_heap_object_clone; spl_handler_SplPriorityQueue.count_elements = spl_heap_object_count_elements; - spl_handler_SplPriorityQueue.get_debug_info = spl_pqueue_object_get_debug_info; spl_handler_SplPriorityQueue.get_gc = spl_pqueue_object_get_gc; spl_handler_SplPriorityQueue.dtor_obj = zend_objects_destroy_object; spl_handler_SplPriorityQueue.free_obj = spl_heap_object_free_storage; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index ba29e0311e493..70126faefe28e 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -279,7 +279,7 @@ static zend_object *spl_object_storage_clone(zval *zobject) } /* }}} */ -static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp) /* {{{ */ +static zend_always_inline HashTable* spl_object_storage_debug_info(zval *obj) /* {{{ */ { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(obj); spl_SplObjectStorageElement *element; @@ -289,8 +289,6 @@ static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp) /* {{{ zend_string *zname; HashTable *debug_info; - *is_temp = 1; - props = Z_OBJPROP_P(obj); debug_info = zend_new_array(zend_hash_num_elements(props) + 1); @@ -1279,6 +1277,17 @@ SPL_METHOD(MultipleIterator, key) } /* }}} */ +/* {{{ proto array MultipleIterator::__debugInfo() */ +SPL_METHOD(MultipleIterator, __debugInfo) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ARR(spl_object_storage_debug_info(getThis())); +} +/* }}} */ + ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) ZEND_ARG_INFO(0, infos) @@ -1301,6 +1310,7 @@ static const zend_function_entry spl_funcs_MultipleIterator[] = { SPL_ME(MultipleIterator, getFlags, arginfo_splobject_void, 0) SPL_ME(MultipleIterator, setFlags, arginfo_MultipleIterator_setflags, 0) SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0) + SPL_ME(MultipleIterator, __debugInfo, arginfo_splobject_void, 0) SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0) SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0) SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0) @@ -1323,7 +1333,6 @@ PHP_MINIT_FUNCTION(spl_observer) memcpy(&spl_handler_SplObjectStorage, &std_object_handlers, sizeof(zend_object_handlers)); spl_handler_SplObjectStorage.offset = XtOffsetOf(spl_SplObjectStorage, std); - spl_handler_SplObjectStorage.get_debug_info = spl_object_storage_debug_info; spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects; spl_handler_SplObjectStorage.clone_obj = spl_object_storage_clone; spl_handler_SplObjectStorage.get_gc = spl_object_storage_get_gc; diff --git a/ext/spl/tests/bug69264.phpt b/ext/spl/tests/bug69264.phpt new file mode 100644 index 0000000000000..91ef0220dd24f --- /dev/null +++ b/ext/spl/tests/bug69264.phpt @@ -0,0 +1,86 @@ +--TEST-- +Bug #69264 (__debugInfo() ignored while extending SPL classes) +--FILE-- + 42, 'parent' => count(parent::__debugInfo())]; + } +} + +class MyDoublyLinkedList extends SplDoublyLinkedList { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + +class MyMultipleIterator extends MultipleIterator { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + +class MyArrayObject extends ArrayObject { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + +class MyMaxHeap extends SplMaxHeap { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + +class MyPriorityQueue extends SplPriorityQueue { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + +var_dump( + new MyFileInfo(__FILE__), + new MyDoublyLinkedList(), + new MyMultipleIterator(), + new MyArrayObject(), + new MyMaxHeap(), + new MyPriorityQueue(), +); +?> +--EXPECTF-- +object(MyFileInfo)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(2) +} +object(MyDoublyLinkedList)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(2) +} +object(MyMultipleIterator)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(1) +} +object(MyArrayObject)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(1) +} +object(MyMaxHeap)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(3) +} +object(MyPriorityQueue)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(3) +} \ No newline at end of file From a62f5122481265bd385ad2b6db4ddd998d8a7e70 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 3 Apr 2020 10:58:58 +0200 Subject: [PATCH 2/7] Add missing __debugInfo() implementations --- ext/spl/spl_array.c | 1 + ext/spl/spl_observer.c | 25 +++++++++++++------------ ext/spl/tests/bug69264.phpt | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 151b84e8be237..706c8db15f280 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -2005,6 +2005,7 @@ static const zend_function_entry spl_funcs_ArrayIterator[] = { 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) + SPL_ME(Array, __debugInfo, 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_observer.c b/ext/spl/spl_observer.c index 70126faefe28e..e5073a9ba7a6a 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -943,6 +943,17 @@ SPL_METHOD(SplObjectStorage, __unserialize) object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); } +/* {{{ proto array SplObjectStorage::__debugInfo() */ +SPL_METHOD(SplObjectStorage, __debugInfo) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ARR(spl_object_storage_debug_info(getThis())); +} +/* }}} */ + ZEND_BEGIN_ARG_INFO(arginfo_Object, 0) ZEND_ARG_INFO(0, object) ZEND_END_ARG_INFO(); @@ -981,6 +992,7 @@ static const zend_function_entry spl_funcs_SplObjectStorage[] = { SPL_ME(SplObjectStorage, getInfo, arginfo_splobject_void,0) SPL_ME(SplObjectStorage, setInfo, arginfo_setInfo, 0) SPL_ME(SplObjectStorage, getHash, arginfo_getHash, 0) + SPL_ME(SplObjectStorage, __debugInfo, arginfo_splobject_void,0) /* Countable */ SPL_ME(SplObjectStorage, count, arginfo_splobject_void,0) /* Iterator */ @@ -1277,17 +1289,6 @@ SPL_METHOD(MultipleIterator, key) } /* }}} */ -/* {{{ proto array MultipleIterator::__debugInfo() */ -SPL_METHOD(MultipleIterator, __debugInfo) -{ - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - RETURN_ARR(spl_object_storage_debug_info(getThis())); -} -/* }}} */ - ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) ZEND_ARG_INFO(0, infos) @@ -1310,10 +1311,10 @@ static const zend_function_entry spl_funcs_MultipleIterator[] = { SPL_ME(MultipleIterator, getFlags, arginfo_splobject_void, 0) SPL_ME(MultipleIterator, setFlags, arginfo_MultipleIterator_setflags, 0) SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0) - SPL_ME(MultipleIterator, __debugInfo, arginfo_splobject_void, 0) SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0) SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0) SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0) + SPL_ME(SplObjectStorage, __debugInfo, arginfo_splobject_void, 0) /* Iterator */ SPL_ME(MultipleIterator, rewind, arginfo_splobject_void, 0) SPL_ME(MultipleIterator, valid, arginfo_splobject_void, 0) diff --git a/ext/spl/tests/bug69264.phpt b/ext/spl/tests/bug69264.phpt index 91ef0220dd24f..aa4d39e4a8c3a 100644 --- a/ext/spl/tests/bug69264.phpt +++ b/ext/spl/tests/bug69264.phpt @@ -14,6 +14,12 @@ class MyDoublyLinkedList extends SplDoublyLinkedList { } } +class MyObjectStorage extends SplObjectStorage { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + class MyMultipleIterator extends MultipleIterator { public function __debugInfo() { return ['child' => 42, 'parent' => count(parent::__debugInfo())]; @@ -26,6 +32,12 @@ class MyArrayObject extends ArrayObject { } } +class MyArrayIterator extends ArrayIterator { + public function __debugInfo() { + return ['child' => 42, 'parent' => count(parent::__debugInfo())]; + } +} + class MyMaxHeap extends SplMaxHeap { public function __debugInfo() { return ['child' => 42, 'parent' => count(parent::__debugInfo())]; @@ -41,8 +53,10 @@ class MyPriorityQueue extends SplPriorityQueue { var_dump( new MyFileInfo(__FILE__), new MyDoublyLinkedList(), + new MyObjectStorage(), new MyMultipleIterator(), new MyArrayObject(), + new MyArrayIterator(), new MyMaxHeap(), new MyPriorityQueue(), ); @@ -60,6 +74,12 @@ object(MyDoublyLinkedList)#%d (2) { ["parent"]=> int(2) } +object(MyObjectStorage)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(1) +} object(MyMultipleIterator)#%d (2) { ["child"]=> int(42) @@ -72,6 +92,12 @@ object(MyArrayObject)#%d (2) { ["parent"]=> int(1) } +object(MyArrayIterator)#%d (2) { + ["child"]=> + int(42) + ["parent"]=> + int(1) +} object(MyMaxHeap)#%d (2) { ["child"]=> int(42) From 893320796e356a1c63348afe5233a0f834b1d6d2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 3 Apr 2020 11:15:37 +0200 Subject: [PATCH 3/7] Duplicate HashTable if no temporary HT had been built --- ext/spl/spl_array.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 706c8db15f280..88910bf21b623 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1894,8 +1894,8 @@ SPL_METHOD(Array, __debugInfo) } ht = spl_array_get_debug_info(getThis(), &is_temp); - if (!is_temp && !(GC_FLAGS(ht) & GC_IMMUTABLE)) { - GC_ADDREF(ht); + if (!is_temp) { + ht = zend_array_dup(ht); } RETURN_ARR(ht); From 528e62078cc1576c4573d4d93b6b21bc7d8d9816 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 6 Apr 2020 09:06:17 +0200 Subject: [PATCH 4/7] Move is_temp logic into spl_array_get_debug_info() --- ext/spl/spl_array.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 88910bf21b623..95c6a0c88f3c2 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -822,7 +822,7 @@ static HashTable *spl_array_get_properties_for(zval *object, zend_prop_purpose p return ht; } /* }}} */ -static zend_always_inline HashTable* spl_array_get_debug_info(zval *obj, int *is_temp) /* {{{ */ +static zend_always_inline HashTable* spl_array_get_debug_info(zval *obj) /* {{{ */ { zval *storage; zend_string *zname; @@ -834,11 +834,9 @@ static zend_always_inline HashTable* spl_array_get_debug_info(zval *obj, int *is } if (intern->ar_flags & SPL_ARRAY_IS_SELF) { - *is_temp = 0; - return intern->std.properties; + return zend_array_dup(intern->std.properties); } else { HashTable *debug_info; - *is_temp = 1; debug_info = zend_new_array(zend_hash_num_elements(intern->std.properties) + 1); zend_hash_copy(debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref); @@ -1887,18 +1885,12 @@ SPL_METHOD(Array, __unserialize) SPL_METHOD(Array, __debugInfo) { HashTable *ht; - int is_temp; if (zend_parse_parameters_none() == FAILURE) { return; } - ht = spl_array_get_debug_info(getThis(), &is_temp); - if (!is_temp) { - ht = zend_array_dup(ht); - } - - RETURN_ARR(ht); + RETURN_ARR(spl_array_get_debug_info(getThis())); } /* }}} */ /* {{{ arginfo and function table */ From e9153ebea08431241a8581b532d4a93c2854f750 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 6 Apr 2020 09:09:05 +0200 Subject: [PATCH 5/7] No need to *always* inline --- ext/spl/spl_array.c | 2 +- ext/spl/spl_directory.c | 2 +- ext/spl/spl_dllist.c | 2 +- ext/spl/spl_heap.c | 2 +- ext/spl/spl_observer.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 95c6a0c88f3c2..2ef8513d74f15 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -822,7 +822,7 @@ static HashTable *spl_array_get_properties_for(zval *object, zend_prop_purpose p return ht; } /* }}} */ -static zend_always_inline HashTable* spl_array_get_debug_info(zval *obj) /* {{{ */ +static inline HashTable* spl_array_get_debug_info(zval *obj) /* {{{ */ { zval *storage; zend_string *zname; diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index cb3ae755b673d..d42e6367c2f3e 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -598,7 +598,7 @@ static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, s } /* }}} */ -static zend_always_inline HashTable *spl_filesystem_object_get_debug_info(zval *object) /* {{{ */ +static inline HashTable *spl_filesystem_object_get_debug_info(zval *object) /* {{{ */ { spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(object); zval tmp; diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 648a9ce4c4f61..ce5504da7e560 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -492,7 +492,7 @@ static int spl_dllist_object_count_elements(zval *object, zend_long *count) /* { } /* }}} */ -static zend_always_inline HashTable* spl_dllist_object_get_debug_info(zval *obj) /* {{{{ */ +static inline HashTable* spl_dllist_object_get_debug_info(zval *obj) /* {{{{ */ { spl_dllist_object *intern = Z_SPLDLLIST_P(obj); spl_ptr_llist_element *current = intern->llist->head, *next; diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 948ef0ce66a5d..4aea640c71ece 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -501,7 +501,7 @@ static int spl_heap_object_count_elements(zval *object, zend_long *count) /* {{{ } /* }}} */ -static zend_always_inline HashTable* spl_heap_object_get_debug_info(zend_class_entry *ce, zval *obj) { /* {{{ */ +static inline HashTable* spl_heap_object_get_debug_info(zend_class_entry *ce, zval *obj) { /* {{{ */ spl_heap_object *intern = Z_SPLHEAP_P(obj); zval tmp, heap_array; zend_string *pnstr; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index e5073a9ba7a6a..40b55727eb8ed 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -279,7 +279,7 @@ static zend_object *spl_object_storage_clone(zval *zobject) } /* }}} */ -static zend_always_inline HashTable* spl_object_storage_debug_info(zval *obj) /* {{{ */ +static inline HashTable* spl_object_storage_debug_info(zval *obj) /* {{{ */ { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(obj); spl_SplObjectStorageElement *element; From b26fa824dd098bfb00d5f5ff1116e3e1d33f7632 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 6 Apr 2020 09:13:40 +0200 Subject: [PATCH 6/7] Define MultipleIterator::__debugInfo as alias --- ext/spl/spl_observer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 40b55727eb8ed..f7dd7ef2e0742 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -1311,10 +1311,10 @@ static const zend_function_entry spl_funcs_MultipleIterator[] = { SPL_ME(MultipleIterator, getFlags, arginfo_splobject_void, 0) SPL_ME(MultipleIterator, setFlags, arginfo_MultipleIterator_setflags, 0) SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0) - SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0) - SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0) - SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0) - SPL_ME(SplObjectStorage, __debugInfo, arginfo_splobject_void, 0) + SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0) + SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0) + SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0) + SPL_MA(MultipleIterator, __debugInfo, SplObjectStorage, __debugInfo, arginfo_splobject_void, 0) /* Iterator */ SPL_ME(MultipleIterator, rewind, arginfo_splobject_void, 0) SPL_ME(MultipleIterator, valid, arginfo_splobject_void, 0) From 4b65ec017b3ca9d9f380d5831c7f292a7f70c7ec Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 6 Apr 2020 09:14:17 +0200 Subject: [PATCH 7/7] Add trailing newline --- ext/spl/tests/bug69264.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/spl/tests/bug69264.phpt b/ext/spl/tests/bug69264.phpt index aa4d39e4a8c3a..2f5251d1770ad 100644 --- a/ext/spl/tests/bug69264.phpt +++ b/ext/spl/tests/bug69264.phpt @@ -109,4 +109,4 @@ object(MyPriorityQueue)#%d (2) { int(42) ["parent"]=> int(3) -} \ No newline at end of file +}