]> granicus.if.org Git - php/commitdiff
Fix several recursion problems when var_dump'ing self-referencing objects
authorEtienne Kneuss <colder@php.net>
Thu, 13 Aug 2009 22:07:05 +0000 (22:07 +0000)
committerEtienne Kneuss <colder@php.net>
Thu, 13 Aug 2009 22:07:05 +0000 (22:07 +0000)
ext/spl/spl_array.c
ext/spl/spl_dllist.c
ext/spl/spl_heap.c
ext/spl/spl_observer.c
ext/spl/tests/SplObjectStorage_var_dump.phpt [new file with mode: 0644]
ext/spl/tests/array_027.phpt [new file with mode: 0644]
ext/spl/tests/dllist_012.phpt [new file with mode: 0644]
ext/spl/tests/heap_012.phpt [new file with mode: 0644]

index 4d23af5820ad4e5aeb40f664032afef75b63f8df..25d53ad5906108a5b80b553ee75611eedf731880 100755 (executable)
@@ -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;
        }
 }
 /* }}} */
index 9d82f2d0f9defa5ed7e0563e4640dbbefe2627a4..6460adf633e3fae845fc80aca701cbf70ba42e40 100644 (file)
@@ -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;
 }
 /* }}}} */
 
index 1a53c7af159a1ab7419bdf4419c9c0a189fca0a2..7de5560e7b865d2721f0864ba886f9fda3f51a5c 100644 (file)
@@ -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;
 }
 /* }}} */
 
index 8aa46310740fa8b881ba7795bad0a58966ce6ec6..b3f2e5531e8791b64d7bc5de349cec24685caffc 100755 (executable)
@@ -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 (file)
index 0000000..9e6f64c
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+SPL: SplObjectStorage: recursive var_dump
+--FILE--
+<?php
+$o = new SplObjectStorage();
+
+$o[new StdClass] = $o;
+
+var_dump($o);
+--EXPECTF--
+object(SplObjectStorage)#1 (1) {
+  [u"storage":u"SplObjectStorage":private]=>
+  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 (file)
index 0000000..aa8cc15
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+SPL: ArrayObject revursive var_dump
+--FILE--
+<?php
+class AO extends ArrayObject {
+}
+$o = new AO();
+$o['plop'] = $o;
+
+var_dump($o);
+--EXPECTF--
+object(AO)#1 (1) {
+  [u"storage":u"ArrayObject":private]=>
+  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 (file)
index 0000000..5a4e8af
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+SPL: DoublyLinkedList: recursive var_dump
+--FILE--
+<?php
+$a = new SplDoublyLinkedList;
+$a[] = $a;
+
+var_dump($a);
+?>
+===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 (file)
index 0000000..6dc1fdc
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+SPL: SplHeap recursive var_dump
+--FILE--
+<?php
+$a = new SplMaxHeap;
+$a->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===