Patch bug60139.php5.4.diff for Performance problem Bug #60139
Patch version 2011-10-29 10:23 UTC
Return to Bug #60139 |
Download this patch
Patch Revisions:
Developer: arnaud.lb@gmail.com
diff --git a/Zend/tests/bug60139-1.phpt b/Zend/tests/bug60139-1.phpt
new file mode 100644
index 0000000..96d0a28
--- /dev/null
+++ b/Zend/tests/bug60139-1.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Closure and GC - 1 (bug #60139)
+--FILE--
+<?php
+
+class c {
+
+ public $foo;
+
+ public function __construct()
+ {
+ $this->foo = function() {};
+ }
+
+ public function __destruct()
+ {
+ echo "destruct\n";
+ }
+}
+
+new c;
+gc_collect_cycles();
+
+
+echo "end\n";
+
+--EXPECT--
+destruct
+end
diff --git a/Zend/tests/bug60139-2.phpt b/Zend/tests/bug60139-2.phpt
new file mode 100644
index 0000000..43721c9
--- /dev/null
+++ b/Zend/tests/bug60139-2.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Closure and GC - 2 (bug #60139)
+--FILE--
+<?php
+
+class c {
+
+ public $foo;
+
+ public function __construct()
+ {
+ $this->foo = get_closure($this);
+ }
+
+ public function __destruct()
+ {
+ echo "destruct\n";
+ }
+}
+
+function get_closure($x) {
+ return function() use ($x) {};
+}
+
+new c;
+gc_collect_cycles();
+
+
+echo "end\n";
+
+--EXPECT--
+destruct
+end
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index 344e600..ef26477 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -318,6 +318,61 @@ int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function
}
/* }}} */
+/* overriden for garbage collection
+ * This is very hacky, but unfortunately the garbage collector can only query objects for
+ * dependencies through get_properties */
+static HashTable *zend_closure_get_properties(zval *object TSRMLS_DC)
+{
+ zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *props;
+ zval *gcdata_arr = NULL;
+ zval **gcdata_arr_pp;
+
+ props = std_object_handlers.get_properties(object TSRMLS_CC);
+
+ if (!GC_G(gc_active)) {
+ zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
+ return props;
+ }
+
+ if (props->nApplyCount > 0) {
+ return props;
+ }
+
+ if (zend_hash_find(props, "\x00gcdata", sizeof("\x00gcdata"), (void**) &gcdata_arr_pp) == SUCCESS) {
+ gcdata_arr = *gcdata_arr_pp;
+ zend_hash_clean(Z_ARRVAL_P(gcdata_arr));
+ }
+
+ if (gcdata_arr == NULL) {
+ MAKE_STD_ZVAL(gcdata_arr);
+ array_init(gcdata_arr);
+ /* don't decrease refcount of members when destroying */
+ Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL;
+
+ /* name starts with to make tampering in user-land more difficult */
+ zend_hash_add(props, "\x00gcdata", sizeof("\x00gcdata"), &gcdata_arr, sizeof(gcdata_arr), NULL);
+ }
+
+ if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
+ HashTable * static_variables = closure->func.op_array.static_variables;
+ HashPosition pos;
+ zval *val;
+
+ zend_hash_internal_pointer_reset_ex(static_variables, &pos);
+ while (zend_hash_get_current_data_ex(static_variables, (void **)&val, &pos) == SUCCESS) {
+ zend_hash_next_index_insert(Z_ARRVAL_P(gcdata_arr), val, sizeof(zval*), NULL);
+ zend_hash_move_forward_ex(static_variables, &pos);
+ }
+ }
+
+ if (closure->this_ptr) {
+ zend_hash_next_index_insert(Z_ARRVAL_P(gcdata_arr), (void**)&closure->this_ptr, sizeof(zval*), NULL);
+ }
+
+ return props;
+}
+
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);
@@ -423,6 +478,7 @@ void zend_register_closure_ce(TSRMLS_D) /* {{{ */
closure_handlers.unset_property = zend_closure_unset_property;
closure_handlers.compare_objects = zend_closure_compare_objects;
closure_handlers.clone_obj = zend_closure_clone;
+ closure_handlers.get_properties = zend_closure_get_properties;
closure_handlers.get_debug_info = zend_closure_get_debug_info;
closure_handlers.get_closure = zend_closure_get_closure;
}
|