]> granicus.if.org Git - php/commitdiff
Fixed bug #60139 (Anonymous functions create cycles not detected by the GC)
authorDmitry Stogov <dmitry@php.net>
Wed, 2 Nov 2011 06:31:33 +0000 (06:31 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 2 Nov 2011 06:31:33 +0000 (06:31 +0000)
Zend/tests/bug60139.phpt [new file with mode: 0644]
Zend/zend_closures.c
Zend/zend_gc.c
Zend/zend_object_handlers.c
Zend/zend_object_handlers.h

diff --git a/Zend/tests/bug60139.phpt b/Zend/tests/bug60139.phpt
new file mode 100644 (file)
index 0000000..414fa56
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Bug #60139 (Anonymous functions create cycles not detected by the GC)
+--FILE--
+<?php
+class Foo {
+    public $x;
+
+    public function __construct() {
+        $this->x = function() {};
+    }
+}
+
+class Bar {
+    public $x;
+
+    public function __construct() {
+        $self = $this;
+        $this->x = function() use ($self) {};
+    }
+}
+
+gc_collect_cycles();
+new Foo;
+var_dump(gc_collect_cycles());
+new Bar;
+var_dump(gc_collect_cycles());
+?>
+--EXPECT--
+int(2)
+int(2)
index 344e6002d50e8cceaad18a93af83edf11506de74..4bdcbd34aeff7bca785578c4c97b27553f4f456b 100644 (file)
@@ -376,6 +376,17 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_
 }
 /* }}} */
 
+static HashTable *zend_closure_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{ */
+{
+       zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
+
+       *table = closure->this_ptr ? &closure->this_ptr : NULL;
+       *n = closure->this_ptr ? 1 : 0;
+       return (closure->func.type == ZEND_USER_FUNCTION) ?
+               closure->func.op_array.static_variables : NULL;
+}
+/* }}} */
+
 /* {{{ proto Closure::__construct()
    Private constructor preventing instantiation */
 ZEND_METHOD(Closure, __construct)
@@ -425,6 +436,7 @@ void zend_register_closure_ce(TSRMLS_D) /* {{{ */
        closure_handlers.clone_obj = zend_closure_clone;
        closure_handlers.get_debug_info = zend_closure_get_debug_info;
        closure_handlers.get_closure = zend_closure_get_closure;
+       closure_handlers.get_gc = zend_closure_get_gc;
 }
 /* }}} */
 
index 4484768f63ed3c29e8c56ba269989fe46f9b27ca..c93ea16cadc50efb8ad786557e8e63bc04a0949d 100644 (file)
@@ -194,7 +194,7 @@ ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
 {
        struct _store_object *obj;
 
-       if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL ||
+       if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_gc == NULL ||
            EG(objects_store).object_buckets == NULL)) {
                return;
        }
@@ -275,48 +275,38 @@ tail_call:
        GC_ZVAL_SET_BLACK(pz);
 
        if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
-               zend_object_get_properties_t get_props;
+               zend_object_get_gc_t get_gc;
                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                obj->refcount++;
                if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
                        GC_SET_BLACK(obj->buffered);
                        if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                    (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                               if (get_props == zend_std_get_properties) {
-                                       zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                                       if (!zobj->properties) {
-                                               int i;
-                                               int n = zobj->ce->default_properties_count;
-
-                                               while (n > 0 && !zobj->properties_table[n-1]) n--;
-                                               for (i = 0; i < n; i++) {
-                                                       if (zobj->properties_table[i]) {
-                                                               pz = zobj->properties_table[i];
-                                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                                       pz->refcount__gc++;
-                                                               }
-                                                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
-                                                                       if (i == n - 1) {
-                                                                               goto tail_call;
-                                                                       } else {
-                                                                               zval_scan_black(pz TSRMLS_CC);
-                                                                       }
-                                                               }
+                                    (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                               int i, n;
+                               zval **table;
+                               HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+                               while (n > 0 && !table[n-1]) n--;
+                               for (i = 0; i < n; i++) {
+                                       if (table[i]) {
+                                               pz = table[i];
+                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                       pz->refcount__gc++;
+                                               }
+                                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
+                                                       if (!props && i == n - 1) {
+                                                               goto tail_call;
+                                                       } else {
+                                                               zval_scan_black(pz TSRMLS_CC);
                                                        }
                                                }
-                                               return;
-                                       } else {
-                                               p = zobj->properties->pListHead;
-                                       }
-                               } else {
-                                       HashTable *props = get_props(pz TSRMLS_CC);
-                                       if(!props) {
-                                               return;
                                        }
-                                       p = props->pListHead;
                                }
+                               if (!props) {
+                                       return;
+                               }
+                               p = props->pListHead;
                        }
                }
        } else if (Z_TYPE_P(pz) == IS_ARRAY) {
@@ -343,39 +333,30 @@ tail_call:
 static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
 {
        Bucket *p;
-       zend_object_get_properties_t get_props;
+       zend_object_get_gc_t get_gc;
 
        GC_SET_BLACK(obj->buffered);
        if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                    (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-               if (get_props == zend_std_get_properties) {
-                       zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                       if (!zobj->properties) {
-                               int i;
-
-                               for (i = 0; i < zobj->ce->default_properties_count; i++) {
-                                       if (zobj->properties_table[i]) {
-                                               pz = zobj->properties_table[i];
-                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                       pz->refcount__gc++;
-                                               }
-                                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
-                                                       zval_scan_black(pz TSRMLS_CC);
-                                               }
-                    }
+                    (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+               int i, n;
+               zval **table;
+               HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+               for (i = 0; i < n; i++) {
+                       if (table[i]) {
+                               pz = table[i];
+                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                       pz->refcount__gc++;
+                               }
+                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
+                                       zval_scan_black(pz TSRMLS_CC);
                                }
-                               return;
-                       } else {
-                               p = zobj->properties->pListHead;
-                       }
-               } else {
-                       HashTable *props = get_props(pz TSRMLS_CC);
-                       if(!props) {
-                               return;
                        }
-                       p = props->pListHead;
                }
+               if (!props) {
+                       return;
+               }
+               p = props->pListHead;
                while (p != NULL) {
                        pz = *(zval**)p->pData;
                        if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
@@ -400,7 +381,7 @@ tail_call:
                GC_ZVAL_SET_COLOR(pz, GC_GREY);
 
                if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
-                       zend_object_get_properties_t get_props;
+                       zend_object_get_gc_t get_gc;
                        struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                        obj->refcount--;
@@ -408,39 +389,29 @@ tail_call:
                                GC_BENCH_INC(zobj_marked_grey);
                                GC_SET_COLOR(obj->buffered, GC_GREY);
                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                                       if (get_props == zend_std_get_properties) {
-                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                                               if (!zobj->properties) {
-                                                       int i;
-                                                       int n = zobj->ce->default_properties_count;
-
-                                                       while (n > 0 && !zobj->properties_table[n-1]) n--;
-                                                       for (i = 0; i < n; i++) {
-                                                               if (zobj->properties_table[i]) {
-                                                                       pz = zobj->properties_table[i];
-                                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                                               pz->refcount__gc--;
-                                                                       }
-                                                                       if (i == n - 1) {
-                                                                               goto tail_call;
-                                                                       } else {
-                                                                               zval_mark_grey(pz TSRMLS_CC);
-                                                                       }
-                                                               }
+                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                                       int i, n;
+                                       zval **table;
+                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+                                       while (n > 0 && !table[n-1]) n--;
+                                       for (i = 0; i < n; i++) {
+                                               if (table[i]) {
+                                                       pz = table[i];
+                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                               pz->refcount__gc--;
+                                                       }
+                                                       if (!props && i == n - 1) {
+                                                               goto tail_call;
+                                                       } else {
+                                                               zval_mark_grey(pz TSRMLS_CC);
                                                        }
-                                                       return;
-                                               } else {
-                                                       p = zobj->properties->pListHead;
-                                               }
-                                       } else {
-                                               HashTable *props = get_props(pz TSRMLS_CC);
-                                               if(!props) {
-                                                       return;
                                                }
-                                               p = props->pListHead;
                                        }
+                                       if (!props) {
+                                               return;
+                                       }
+                                       p = props->pListHead;
                                }
                        }
                } else if (Z_TYPE_P(pz) == IS_ARRAY) {
@@ -468,39 +439,30 @@ tail_call:
 static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
 {
        Bucket *p;
-       zend_object_get_properties_t get_props;
+       zend_object_get_gc_t get_gc;
 
        if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
                GC_BENCH_INC(zobj_marked_grey);
                GC_SET_COLOR(obj->buffered, GC_GREY);
                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                       if (get_props == zend_std_get_properties) {
-                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                               if (!zobj->properties) {
-                                       int i;
-
-                                       for (i = 0; i < zobj->ce->default_properties_count; i++) {
-                                               if (zobj->properties_table[i]) {
-                                                       pz = zobj->properties_table[i];
-                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                               pz->refcount__gc--;
-                                                       }
-                                                       zval_mark_grey(pz TSRMLS_CC);
-                       }
+                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                       int i, n;
+                       zval **table;
+                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+                       for (i = 0; i < n; i++) {
+                               if (table[i]) {
+                                       pz = table[i];
+                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                               pz->refcount__gc--;
                                        }
-                                       return;
-                               } else {
-                                       p = zobj->properties->pListHead;
-                               }
-                       } else {
-                               HashTable *props = get_props(pz TSRMLS_CC);
-                               if(!props) {
-                                       return;
+                                       zval_mark_grey(pz TSRMLS_CC);
                                }
-                               p = props->pListHead;
                        }
+                       if (!props) {
+                               return;
+                       }
+                       p = props->pListHead;
                        while (p != NULL) {
                                pz = *(zval**)p->pData;
                                if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
@@ -558,7 +520,7 @@ tail_call:
                } else {
                        GC_ZVAL_SET_COLOR(pz, GC_WHITE);
                        if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
-                               zend_object_get_properties_t get_props;
+                               zend_object_get_gc_t get_gc;
                                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                                if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
@@ -567,36 +529,26 @@ tail_call:
                                        } else {
                                                GC_SET_COLOR(obj->buffered, GC_WHITE);
                                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                                                       if (get_props == zend_std_get_properties) {
-                                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                                                               if (!zobj->properties) {
-                                                                       int i;
-                                                                       int n = zobj->ce->default_properties_count;
-
-                                                                       while (n > 0 && !zobj->properties_table[n-1]) n--;
-                                                                       for (i = 0; i < n; i++) {
-                                                                               if (zobj->properties_table[i]) {
-                                                                                       pz = zobj->properties_table[i];
-                                                                                       if (i == n - 1) {
-                                                                                               goto tail_call;
-                                                                                       } else {
-                                                                                               zval_scan(pz TSRMLS_CC);
-                                                                                       }
-                                                                               }
+                                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                                                       int i, n;
+                                                       zval **table;
+                                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+                                                       while (n > 0 && !table[n-1]) n--;
+                                                       for (i = 0; i < n; i++) {
+                                                               if (table[i]) {
+                                                                       pz = table[i];
+                                                                       if (!props && i == n - 1) {
+                                                                               goto tail_call;
+                                                                       } else {
+                                                                               zval_scan(pz TSRMLS_CC);
                                                                        }
-                                                                       return;
-                                                               } else {
-                                                                       p = zobj->properties->pListHead;
-                                                               }
-                                                       } else {
-                                                               HashTable *props = get_props(pz TSRMLS_CC);
-                                                               if(!props) {
-                                                                       return;
                                                                }
-                                                               p = props->pListHead;
                                                        }
+                                                       if (!props) {
+                                                               return;
+                                                       }
+                                                       p = props->pListHead;
                                                }
                                        }
                                }
@@ -623,7 +575,7 @@ tail_call:
 static void zobj_scan(zval *pz TSRMLS_DC)
 {
        Bucket *p;
-       zend_object_get_properties_t get_props;
+       zend_object_get_gc_t get_gc;
 
        if (EG(objects_store).object_buckets) {
                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
@@ -634,30 +586,21 @@ static void zobj_scan(zval *pz TSRMLS_DC)
                        } else {
                                GC_SET_COLOR(obj->buffered, GC_WHITE);
                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                                       if (get_props == zend_std_get_properties) {
-                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                                               if (!zobj->properties) {
-                                                       int i;
-
-                                                       for (i = 0; i < zobj->ce->default_properties_count; i++) {
-                                                               if (zobj->properties_table[i]) {
-                                                                       pz = zobj->properties_table[i];
-                                                                       zval_scan(pz TSRMLS_CC);
-                                       }
-                                                       }
-                                                       return;
-                                               } else {
-                                                       p = zobj->properties->pListHead;
-                                               }
-                                       } else {
-                                               HashTable *props = get_props(pz TSRMLS_CC);
-                                               if(!props) {
-                                                       return;
-                                               }
-                                               p = props->pListHead;
+                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                                       int i, n;
+                                       zval **table;
+                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+                                       for (i = 0; i < n; i++) {
+                                               if (table[i]) {
+                                                       pz = table[i];
+                                                       zval_scan(pz TSRMLS_CC);
+                       }
+                                       }
+                                       if (!props) {
+                                               return;
                                        }
+                                       p = props->pListHead;
                                        while (p != NULL) {
                                                zval_scan(*(zval**)p->pData TSRMLS_CC);
                                                p = p->pListNext;
@@ -697,52 +640,44 @@ tail_call:
                GC_ZVAL_SET_BLACK(pz);
 
                if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
-                       zend_object_get_properties_t get_props;
+                       zend_object_get_gc_t get_gc;
                        struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                        if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
                                GC_SET_BLACK(obj->buffered);
 
                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                                       if (get_props == zend_std_get_properties) {
-                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                                       int i, n;
+                                       zval **table, *zv;
+                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
 
-                                               if (!zobj->properties) {
-                                                       int i;
-                                                       int n = zobj->ce->default_properties_count;
-
-                                                       while (n > 0 && !zobj->properties_table[n-1]) n--;
-
-                                                       /* restore refcount and put into list to free */
-                                                       pz->refcount__gc++;
-                                                       ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
-                                                       GC_G(zval_to_free) = (zval_gc_info*)pz;
+                                       if (!props) {
+                                               /* restore refcount and put into list to free */
+                                               pz->refcount__gc++;
+                                               ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
+                                               GC_G(zval_to_free) = (zval_gc_info*)pz;
+                                       }
 
-                                                       for (i = 0; i < n; i++) {
-                                                               if (zobj->properties_table[i]) {
-                                                                       pz = zobj->properties_table[i];
-                                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                                               pz->refcount__gc++;
-                                                                       }
-                                                                       if (i == n - 1) {
-                                                                               goto tail_call;
-                                                                       } else {
-                                                                               zval_collect_white(pz TSRMLS_CC);
-                                                                       }
-                                                               }
+                                       while (n > 0 && !table[n-1]) n--;
+                                       for (i = 0; i < n; i++) {
+                                               if (table[i]) {
+                                                       zv = table[i];
+                                                       if (Z_TYPE_P(zv) != IS_ARRAY || Z_ARRVAL_P(zv) != &EG(symbol_table)) {
+                                                               zv->refcount__gc++;
+                                                       }
+                                                       if (!props && i == n - 1) {
+                                                               pz = zv;
+                                                               goto tail_call;
+                                                       } else {
+                                                               zval_collect_white(zv TSRMLS_CC);
                                                        }
-                                                       return;
-                                               } else {
-                                                       p = zobj->properties->pListHead;
-                                               }
-                                       } else {
-                                               HashTable *props = get_props(pz TSRMLS_CC);
-                                               if(!props) {
-                                                       return;
                                                }
-                                               p = props->pListHead;
                                        }
+                                       if (!props) {
+                                               return;
+                                       }
+                                       p = props->pListHead;
                                }
                        }
                } else {
@@ -776,40 +711,31 @@ static void zobj_collect_white(zval *pz TSRMLS_DC)
        Bucket *p;
 
        if (EG(objects_store).object_buckets) {
-               zend_object_get_properties_t get_props;
+               zend_object_get_gc_t get_gc;
                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
                        GC_SET_BLACK(obj->buffered);
 
                        if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                    (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
-                               if (get_props == zend_std_get_properties) {
-                                       zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
-
-                                       if (!zobj->properties) {
-                                               int i;
-
-                                               for (i = 0; i < zobj->ce->default_properties_count; i++) {
-                                                       if (zobj->properties_table[i]) {
-                                                               pz = zobj->properties_table[i];
-                                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                                       pz->refcount__gc++;
-                                                               }
-                                                               zval_collect_white(pz TSRMLS_CC);
-                                                       }
+                                    (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
+                               int i, n;
+                               zval **table;
+                               HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+
+                               for (i = 0; i < n; i++) {
+                                       if (table[i]) {
+                                               pz = table[i];
+                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                       pz->refcount__gc++;
                                                }
-                                               return;
-                                       } else {
-                                               p = zobj->properties->pListHead;
+                                               zval_collect_white(pz TSRMLS_CC);
                                        }
-                               } else {
-                                       HashTable *props = get_props(pz TSRMLS_CC);
-                                       if(!props) {
-                                               return;
-                                       }
-                                       p = props->pListHead;
                                }
+                               if (!props) {
+                                       return;
+                               }
+                               p = props->pListHead;
                                while (p != NULL) {
                                        pz = *(zval**)p->pData;
                                        if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
index 77fdea3e6239f7d5a51ef0ec928d3f8f527691f7..b43021dd22950c4e3ae948a7894c65b84a158af5 100644 (file)
@@ -102,6 +102,28 @@ ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC) /* {{{ */
 }
 /* }}} */
 
+ZEND_API HashTable *zend_std_get_gc(zval *object, zval ***table, int *n TSRMLS_DC) /* {{{ */
+{
+       if (Z_OBJ_HANDLER_P(object, get_properties) != zend_std_get_properties) {
+               *table = NULL;
+               *n = 0;
+               return Z_OBJ_HANDLER_P(object, get_properties)(object TSRMLS_CC);
+       } else {
+               zend_object *zobj = Z_OBJ_P(object);
+
+               if (zobj->properties) {
+                       *table = NULL;
+                       *n = 0;
+                       return zobj->properties;
+               } else {
+                       *table = zobj->properties_table;
+                       *n = zobj->ce->default_properties_count;
+                       return NULL;
+               }
+       }
+}
+/* }}} */
+
 ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
 {
        *is_temp = 0;
@@ -1584,6 +1606,7 @@ ZEND_API zend_object_handlers std_object_handlers = {
        NULL,                                                                   /* count_elements */
        NULL,                                                                   /* get_debug_info */
        zend_std_get_closure,                                   /* get_closure */
+       zend_std_get_gc,                                                /* get_gc */
 };
 
 /*
index 8e830d16e62b24abe7f01aed0ae2029e1075b8a0..d318ffc40170a40a6a7452866d038cc4da95056e 100644 (file)
@@ -111,6 +111,8 @@ typedef int (*zend_object_count_elements_t)(zval *object, long *count TSRMLS_DC)
 
 typedef int (*zend_object_get_closure_t)(zval *obj, zend_class_entry **ce_ptr, union _zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC);
 
+typedef HashTable *(*zend_object_get_gc_t)(zval *object, zval ***table, int *n TSRMLS_DC);
+
 struct _zend_object_handlers {
        /* general object functions */
        zend_object_add_ref_t                                   add_ref;
@@ -139,6 +141,7 @@ struct _zend_object_handlers {
        zend_object_count_elements_t                    count_elements;
        zend_object_get_debug_info_t                    get_debug_info;
        zend_object_get_closure_t                               get_closure;
+       zend_object_get_gc_t                                    get_gc;
 };
 
 extern ZEND_API zend_object_handlers std_object_handlers;