colder Mon, 10 Aug 2009 15:18:13 +0000
Revision: http://svn.php.net/viewvc?view=revision&revision=287043
Log:
Fix endless recursion of var_dump() over self-referencing closures
Changed paths:
A php/php-src/branches/PHP_5_3/Zend/tests/closure_034.phpt
U php/php-src/branches/PHP_5_3/Zend/zend_closures.c
A php/php-src/trunk/Zend/tests/closure_034.phpt
U php/php-src/trunk/Zend/zend_closures.c
Added: php/php-src/branches/PHP_5_3/Zend/tests/closure_034.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/tests/closure_034.phpt (rev 0)
+++ php/php-src/branches/PHP_5_3/Zend/tests/closure_034.phpt 2009-08-10 15:18:13 UTC (rev 287043)
@@ -0,0 +1,25 @@
+--TEST--
+Closure 033: Recursive var_dump on closures
+--FILE--
+<?php
+
+$a = function () use(&$a) {};
+var_dump($a);
+
+?>
+===DONE===
+--EXPECTF--
+object(Closure)#1 (1) {
+ ["static"]=>
+ array(1) {
+ ["a"]=>
+ &object(Closure)#1 (1) {
+ ["static"]=>
+ array(1) {
+ ["a"]=>
+ *RECURSION*
+ }
+ }
+ }
+}
+===DONE===
Modified: php/php-src/branches/PHP_5_3/Zend/zend_closures.c
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/zend_closures.c 2009-08-10 14:01:03 UTC (rev 287042)
+++ php/php-src/branches/PHP_5_3/Zend/zend_closures.c 2009-08-10 15:18:13 UTC (rev 287043)
@@ -37,6 +37,7 @@
typedef struct _zend_closure {
zend_object std;
zend_function func;
+ HashTable *debug_info;
} zend_closure;
/* non-static since it needs to be referenced */
@@ -179,6 +180,11 @@
destroy_op_array(&closure->func.op_array TSRMLS_CC);
}
+ if (closure->debug_info != NULL) {
+ zend_hash_destroy(closure->debug_info);
+ efree(closure->debug_info);
+ }
+
efree(closure);
}
/* }}} */
@@ -222,48 +228,53 @@
static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
{
zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
- HashTable *rv;
zval *val;
struct _zend_arg_info *arg_info = closure->func.common.arg_info;
- *is_temp = 1;
- ALLOC_HASHTABLE(rv);
- zend_hash_init(rv, 1, NULL, ZVAL_PTR_DTOR, 0);
- if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
- HashTable *static_variables = closure->func.op_array.static_variables;
- MAKE_STD_ZVAL(val);
- array_init(val);
- zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
- zend_symtable_update(rv, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
+ *is_temp = 0;
+
+ if (closure->debug_info == NULL) {
+ ALLOC_HASHTABLE(closure->debug_info);
+ zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
}
+ if (closure->debug_info->nApplyCount == 0) {
+ if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
+ HashTable *static_variables = closure->func.op_array.static_variables;
+ MAKE_STD_ZVAL(val);
+ array_init(val);
+ zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
+ zend_symtable_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
+ }
- if (arg_info) {
- zend_uint i, required = closure->func.common.required_num_args;
+ if (arg_info) {
+ zend_uint i, required = closure->func.common.required_num_args;
- MAKE_STD_ZVAL(val);
- array_init(val);
+ MAKE_STD_ZVAL(val);
+ array_init(val);
- for (i = 0; i < closure->func.common.num_args; i++) {
- char *name, *info;
- int name_len, info_len;
- if (arg_info->name) {
- name_len = zend_spprintf(&name, 0, "%s$%s",
- arg_info->pass_by_reference ? "&" : "",
- arg_info->name);
- } else {
- name_len = zend_spprintf(&name, 0, "%s$param%d",
- arg_info->pass_by_reference ? "&" : "",
- i + 1);
+ for (i = 0; i < closure->func.common.num_args; i++) {
+ char *name, *info;
+ int name_len, info_len;
+ if (arg_info->name) {
+ name_len = zend_spprintf(&name, 0, "%s$%s",
+ arg_info->pass_by_reference ? "&" : "",
+ arg_info->name);
+ } else {
+ name_len = zend_spprintf(&name, 0, "%s$param%d",
+ arg_info->pass_by_reference ? "&" : "",
+ i + 1);
+ }
+ info_len = zend_spprintf(&info, 0, "%s",
+ i >= required ? "<optional>" : "<required>");
+ add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
+ efree(name);
+ arg_info++;
}
- info_len = zend_spprintf(&info, 0, "%s",
- i >= required ? "<optional>" : "<required>");
- add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
- efree(name);
- arg_info++;
+ zend_symtable_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
}
- zend_symtable_update(rv, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
}
- return rv;
+
+ return closure->debug_info;
}
/* }}} */
Added: php/php-src/trunk/Zend/tests/closure_034.phpt
===================================================================
--- php/php-src/trunk/Zend/tests/closure_034.phpt (rev 0)
+++ php/php-src/trunk/Zend/tests/closure_034.phpt 2009-08-10 15:18:13 UTC (rev 287043)
@@ -0,0 +1,29 @@
+--TEST--
+Closure 033: Recursive var_dump on closures
+--FILE--
+<?php
+
+$a = function () use(&$a) {};
+var_dump($a);
+
+?>
+===DONE===
+--EXPECTF--
+object(Closure)#1 (2) {
+ ["this"]=>
+ NULL
+ ["static"]=>
+ array(1) {
+ [u"a"]=>
+ &object(Closure)#1 (2) {
+ ["this"]=>
+ NULL
+ ["static"]=>
+ array(1) {
+ [u"a"]=>
+ *RECURSION*
+ }
+ }
+ }
+}
+===DONE===
Modified: php/php-src/trunk/Zend/zend_closures.c
===================================================================
--- php/php-src/trunk/Zend/zend_closures.c 2009-08-10 14:01:03 UTC (rev 287042)
+++ php/php-src/trunk/Zend/zend_closures.c 2009-08-10 15:18:13 UTC (rev 287043)
@@ -38,6 +38,7 @@
zend_object std;
zend_function func;
zval *this_ptr;
+ HashTable *debug_info;
} zend_closure;
/* non-static since it needs to be referenced */
@@ -192,6 +193,11 @@
zval_ptr_dtor(&closure->this_ptr);
}
+ if (closure->debug_info != NULL) {
+ zend_hash_destroy(closure->debug_info);
+ efree(closure->debug_info);
+ }
+
efree(closure);
}
/* }}} */
@@ -242,55 +248,60 @@
static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
{
zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
- HashTable *rv;
zval *val;
struct _zend_arg_info *arg_info = closure->func.common.arg_info;
- *is_temp = 1;
- ALLOC_HASHTABLE(rv);
- zend_hash_init(rv, 1, NULL, ZVAL_PTR_DTOR, 0);
- val = closure->this_ptr;
- if (!val) {
- ALLOC_INIT_ZVAL(val);
- } else {
- Z_ADDREF_P(val);
+ *is_temp = 0;
+
+ if (closure->debug_info == NULL) {
+ ALLOC_HASHTABLE(closure->debug_info);
+ zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
}
- zend_symtable_update(rv, "this", sizeof("this"), (void *) &val, sizeof(zval *), NULL);
- if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
- HashTable *static_variables = closure->func.op_array.static_variables;
- MAKE_STD_ZVAL(val);
- array_init(val);
- zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
- zend_symtable_update(rv, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
- }
- if (arg_info) {
- zend_uint i, required = closure->func.common.required_num_args;
+ if (closure->debug_info->nApplyCount == 0) {
+ val = closure->this_ptr;
+ if (!val) {
+ ALLOC_INIT_ZVAL(val);
+ } else {
+ Z_ADDREF_P(val);
+ }
+ zend_symtable_update(closure->debug_info, "this", sizeof("this"), (void *) &val, sizeof(zval *), NULL);
+ if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
+ HashTable *static_variables = closure->func.op_array.static_variables;
+ MAKE_STD_ZVAL(val);
+ array_init(val);
+ zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
+ zend_symtable_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
+ }
- MAKE_STD_ZVAL(val);
- array_init(val);
+ if (arg_info) {
+ zend_uint i, required = closure->func.common.required_num_args;
- for (i = 0; i < closure->func.common.num_args; i++) {
- char *name, *info;
- int name_len, info_len;
- if (arg_info->name.v) {
- name_len = zend_spprintf(&name, 0, "%s$%v",
- arg_info->pass_by_reference ? "&" : "",
- arg_info->name.v);
- } else {
- name_len = zend_spprintf(&name, 0, "%s$param%d",
- arg_info->pass_by_reference ? "&" : "",
- i + 1);
+ MAKE_STD_ZVAL(val);
+ array_init(val);
+
+ for (i = 0; i < closure->func.common.num_args; i++) {
+ char *name, *info;
+ int name_len, info_len;
+ if (arg_info->name.v) {
+ name_len = zend_spprintf(&name, 0, "%s$%v",
+ arg_info->pass_by_reference ? "&" : "",
+ arg_info->name.v);
+ } else {
+ name_len = zend_spprintf(&name, 0, "%s$param%d",
+ arg_info->pass_by_reference ? "&" : "",
+ i + 1);
+ }
+ info_len = zend_spprintf(&info, 0, "%s",
+ i >= required ? "<optional>" : "<required>");
+ add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
+ efree(name);
+ arg_info++;
}
- info_len = zend_spprintf(&info, 0, "%s",
- i >= required ? "<optional>" : "<required>");
- add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
- efree(name);
- arg_info++;
+ zend_symtable_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
}
- zend_symtable_update(rv, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
}
- return rv;
+ return closure->debug_info;
}
/* }}} */
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php