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

Reply via email to