From: Etienne Kneuss Date: Thu, 13 Aug 2009 22:07:05 +0000 (+0000) Subject: Fix several recursion problems when var_dump'ing self-referencing objects X-Git-Tag: php-5.4.0alpha1~191^2~2803 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=642251da3cbe8fa331accd33c6d3945c1ef7058e;p=php Fix several recursion problems when var_dump'ing self-referencing objects --- diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 4d23af5820..25d53ad590 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -77,6 +77,7 @@ typedef struct _spl_array_object { zend_class_entry *ce_get_iterator; php_serialize_data_t *serialize_data; php_unserialize_data_t *unserialize_data; + HashTable *debug_info; } spl_array_object; static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */ @@ -145,6 +146,11 @@ static void spl_array_object_free_storage(void *object TSRMLS_DC) zval_ptr_dtor(&intern->array); zval_ptr_dtor(&intern->retval); + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + efree(object); } /* }}} */ @@ -173,6 +179,7 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s intern->ar_flags = 0; intern->serialize_data = NULL; intern->unserialize_data = NULL; + intern->debug_info = NULL; intern->ce_get_iterator = spl_ce_ArrayIterator; if (orig) { spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC); @@ -681,32 +688,33 @@ static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */ static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */ { spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC); - HashTable *rv; zval *tmp, *storage; int name_len; zstr zname; zend_class_entry *base; + *is_temp = 0; if (HASH_OF(intern->array) == intern->std.properties) { - *is_temp = 0; return intern->std.properties; } else { - *is_temp = 1; - - ALLOC_HASHTABLE(rv); - ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 1, 0); - - zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - - storage = intern->array; - zval_add_ref(&storage); + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); + } - base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject; - zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC); - zend_u_symtable_update(rv, IS_UNICODE, zname, name_len+1, &storage, sizeof(zval *), NULL); - efree(zname.v); + if (intern->debug_info->nApplyCount == 0) { + zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + storage = intern->array; + zval_add_ref(&storage); + + base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject; + zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC); + zend_u_symtable_update(intern->debug_info, IS_UNICODE, zname, name_len+1, &storage, sizeof(zval *), NULL); + efree(zname.v); + } - return rv; + return intern->debug_info; } } /* }}} */ diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 9d82f2d0f9..6460adf633 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -94,6 +94,7 @@ struct _spl_dllist_object { zend_function *fptr_offset_del; zend_function *fptr_count; zend_class_entry *ce_get_iterator; + HashTable *debug_info; }; /* define an overloaded iterator structure */ @@ -353,6 +354,11 @@ static void spl_dllist_object_free_storage(void *object TSRMLS_DC) /* {{{ */ SPL_LLIST_CHECK_DELREF(intern->traverse_pointer); zval_ptr_dtor(&intern->retval); + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + efree(object); } /* }}} */ @@ -374,6 +380,7 @@ static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type, intern->flags = 0; intern->traverse_position = 0; + intern->debug_info = NULL; if (orig) { spl_dllist_object *other = (spl_dllist_object*)zend_object_store_get_object(orig TSRMLS_CC); @@ -498,44 +505,47 @@ static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp TSRML { spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(obj TSRMLS_CC); spl_ptr_llist_element *current = intern->llist->head, *next; - HashTable *rv; zval *tmp, zrv, *dllist_array; zstr pnstr; int pnlen; int i = 0;; - *is_temp = 1; + *is_temp = 0; - ALLOC_HASHTABLE(rv); - ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 1, 0); + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); + } - INIT_PZVAL(&zrv); - Z_ARRVAL(zrv) = rv; + if (intern->debug_info->nApplyCount == 0) { + INIT_PZVAL(&zrv); + Z_ARRVAL(zrv) = intern->debug_info; - zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); - add_u_assoc_long_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, intern->flags); - efree(pnstr.v); + pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); + add_u_assoc_long_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, intern->flags); + efree(pnstr.v); - ALLOC_INIT_ZVAL(dllist_array); - array_init(dllist_array); + ALLOC_INIT_ZVAL(dllist_array); + array_init(dllist_array); - while (current) { - next = current->next; + while (current) { + next = current->next; - add_index_zval(dllist_array, i, (zval *)current->data); - Z_ADDREF_P(current->data); - i++; + add_index_zval(dllist_array, i, (zval *)current->data); + Z_ADDREF_P(current->data); + i++; - current = next; - } + current = next; + } - pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1, &pnlen TSRMLS_CC); - add_u_assoc_zval_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, dllist_array); - efree(pnstr.v); + pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1, &pnlen TSRMLS_CC); + add_u_assoc_zval_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, dllist_array); + efree(pnstr.v); + } - return rv; + return intern->debug_info; } /* }}}} */ diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 1a53c7af15..7de5560e7b 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -76,6 +76,7 @@ struct _spl_heap_object { zend_class_entry *ce_get_iterator; zend_function *fptr_cmp; zend_function *fptr_count; + HashTable *debug_info; }; /* define an overloaded iterator structure */ @@ -370,6 +371,12 @@ static void spl_heap_object_free_storage(void *object TSRMLS_DC) /* {{{ */ spl_ptr_heap_destroy(intern->heap TSRMLS_CC); zval_ptr_dtor(&intern->retval); + + if(intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + efree(object); } /* }}} */ @@ -389,8 +396,9 @@ static zend_object_value spl_heap_object_new_ex(zend_class_entry *class_type, sp zend_object_std_init(&intern->std, class_type TSRMLS_CC); zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - intern->flags = 0; - intern->fptr_cmp = NULL; + intern->flags = 0; + intern->fptr_cmp = NULL; + intern->debug_info = NULL; if (orig) { spl_heap_object *other = (spl_heap_object*)zend_object_store_get_object(orig TSRMLS_CC); @@ -514,43 +522,46 @@ static int spl_heap_object_count_elements(zval *object, long *count TSRMLS_DC) / static HashTable* spl_heap_object_get_debug_info_helper(zend_class_entry *ce, zval *obj, int *is_temp TSRMLS_DC) { /* {{{ */ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(obj TSRMLS_CC); - HashTable *rv; zval *tmp, zrv, *heap_array; zstr pnstr; int pnlen; int i; - *is_temp = 1; + *is_temp = 0; + + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); + } - ALLOC_HASHTABLE(rv); - ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 1, 0); + if (intern->debug_info->nApplyCount == 0) { + INIT_PZVAL(&zrv); + Z_ARRVAL(zrv) = intern->debug_info; - INIT_PZVAL(&zrv); - Z_ARRVAL(zrv) = rv; + zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + pnstr = spl_gen_private_prop_name(ce, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); + add_u_assoc_long_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, intern->flags); + efree(pnstr.v); - pnstr = spl_gen_private_prop_name(ce, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); - add_u_assoc_long_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, intern->flags); - efree(pnstr.v); + pnstr = spl_gen_private_prop_name(ce, "isCorrupted", sizeof("isCorrupted")-1, &pnlen TSRMLS_CC); + add_u_assoc_bool_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, intern->heap->flags&SPL_HEAP_CORRUPTED); + efree(pnstr.v); - pnstr = spl_gen_private_prop_name(ce, "isCorrupted", sizeof("isCorrupted")-1, &pnlen TSRMLS_CC); - add_u_assoc_bool_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, intern->heap->flags&SPL_HEAP_CORRUPTED); - efree(pnstr.v); + ALLOC_INIT_ZVAL(heap_array); + array_init(heap_array); - ALLOC_INIT_ZVAL(heap_array); - array_init(heap_array); + for (i = 0; i < intern->heap->count; ++i) { + add_index_zval(heap_array, i, (zval *)intern->heap->elements[i]); + Z_ADDREF_P(intern->heap->elements[i]); + } - for (i = 0; i < intern->heap->count; ++i) { - add_index_zval(heap_array, i, (zval *)intern->heap->elements[i]); - Z_ADDREF_P(intern->heap->elements[i]); + pnstr = spl_gen_private_prop_name(ce, "heap", sizeof("heap")-1, &pnlen TSRMLS_CC); + add_u_assoc_zval_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, heap_array); + efree(pnstr.v); } - pnstr = spl_gen_private_prop_name(ce, "heap", sizeof("heap")-1, &pnlen TSRMLS_CC); - add_u_assoc_zval_ex(&zrv, IS_UNICODE, pnstr, pnlen+1, heap_array); - efree(pnstr.v); - - return rv; + return intern->debug_info; } /* }}} */ diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 8aa4631074..b3f2e5531e 100755 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -84,6 +84,7 @@ typedef struct _spl_SplObjectStorage { /* {{{ */ long index; HashPosition pos; long flags; + HashTable *debug_info; } spl_SplObjectStorage; /* }}} */ /* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */ @@ -100,6 +101,13 @@ void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */ zend_hash_destroy(&intern->storage); + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + + } + + efree(object); } /* }}} */ @@ -239,42 +247,46 @@ static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_D { spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC); spl_SplObjectStorageElement *element; - HashTable *rv, *props; + HashTable *props; HashPosition pos; zval *tmp, *storage; char md5str[33]; int name_len; zstr zname; - *is_temp = 1; + *is_temp = 0; props = Z_OBJPROP_P(obj); - ALLOC_HASHTABLE(rv); - ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(props) + 1, 0); - - zend_hash_copy(rv, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(props) + 1, 0); + } - MAKE_STD_ZVAL(storage); - array_init(storage); + if (intern->debug_info->nApplyCount == 0) { + zend_hash_copy(intern->debug_info, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + MAKE_STD_ZVAL(storage); + array_init(storage); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) { + php_spl_object_hash(element->obj, md5str TSRMLS_CC); + Z_ADDREF_P(element->obj); + Z_ADDREF_P(element->inf); + MAKE_STD_ZVAL(tmp); + array_init(tmp); + add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj); + add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf); + add_assoc_zval_ex(storage, md5str, 33, tmp); + zend_hash_move_forward_ex(&intern->storage, &pos); + } - zend_hash_internal_pointer_reset_ex(&intern->storage, &pos); - while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) { - php_spl_object_hash(element->obj, md5str TSRMLS_CC); - Z_ADDREF_P(element->obj); - Z_ADDREF_P(element->inf); - MAKE_STD_ZVAL(tmp); - array_init(tmp); - add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj); - add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf); - add_assoc_zval_ex(storage, md5str, 33, tmp); - zend_hash_move_forward_ex(&intern->storage, &pos); + zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC); + zend_u_symtable_update(intern->debug_info, IS_UNICODE, zname, name_len+1, &storage, sizeof(zval *), NULL); + efree(zname.v); } - zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC); - zend_u_symtable_update(rv, IS_UNICODE, zname, name_len+1, &storage, sizeof(zval *), NULL); - efree(zname.v); - - return rv; + return intern->debug_info; } /* }}} */ diff --git a/ext/spl/tests/SplObjectStorage_var_dump.phpt b/ext/spl/tests/SplObjectStorage_var_dump.phpt new file mode 100644 index 0000000000..9e6f64ce1d --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_var_dump.phpt @@ -0,0 +1,35 @@ +--TEST-- +SPL: SplObjectStorage: recursive var_dump +--FILE-- + + array(1) { + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#2 (0) { + } + ["inf"]=> + object(SplObjectStorage)#1 (1) { + [u"storage":u"SplObjectStorage":private]=> + array(1) { + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#2 (0) { + } + ["inf"]=> + *RECURSION* + } + } + } + } + } +} diff --git a/ext/spl/tests/array_027.phpt b/ext/spl/tests/array_027.phpt new file mode 100644 index 0000000000..aa8cc15091 --- /dev/null +++ b/ext/spl/tests/array_027.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: ArrayObject revursive var_dump +--FILE-- + + array(1) { + [u"plop"]=> + object(AO)#1 (1) { + [u"storage":u"ArrayObject":private]=> + array(1) { + [u"plop"]=> + *RECURSION* + } + } + } +} diff --git a/ext/spl/tests/dllist_012.phpt b/ext/spl/tests/dllist_012.phpt new file mode 100644 index 0000000000..5a4e8af1e1 --- /dev/null +++ b/ext/spl/tests/dllist_012.phpt @@ -0,0 +1,29 @@ +--TEST-- +SPL: DoublyLinkedList: recursive var_dump +--FILE-- + +===DONE=== +--EXPECT-- +object(SplDoublyLinkedList)#1 (2) { + [u"flags":u"SplDoublyLinkedList":private]=> + int(0) + [u"dllist":u"SplDoublyLinkedList":private]=> + array(1) { + [0]=> + object(SplDoublyLinkedList)#1 (2) { + [u"flags":u"SplDoublyLinkedList":private]=> + int(0) + [u"dllist":u"SplDoublyLinkedList":private]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +===DONE=== diff --git a/ext/spl/tests/heap_012.phpt b/ext/spl/tests/heap_012.phpt new file mode 100644 index 0000000000..6dc1fdc7eb --- /dev/null +++ b/ext/spl/tests/heap_012.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: SplHeap recursive var_dump +--FILE-- +insert($a); +var_dump($a) +?> +===DONE=== +--EXPECT-- +object(SplMaxHeap)#1 (3) { + [u"flags":u"SplHeap":private]=> + int(0) + [u"isCorrupted":u"SplHeap":private]=> + bool(false) + [u"heap":u"SplHeap":private]=> + array(1) { + [0]=> + object(SplMaxHeap)#1 (3) { + [u"flags":u"SplHeap":private]=> + int(0) + [u"isCorrupted":u"SplHeap":private]=> + bool(false) + [u"heap":u"SplHeap":private]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +===DONE===