com php-src: Fixed bug #69534 (Cycle leaks through declared properties on internal classes): Zend/tests/bug69534.phpt Zend/zend_gc.c
Zend/zend_object_handlers.c
| From: | Dmitry Stogov | Date: | Wed, 06 May 2015 18:33:49 +0000 |
| Subject: | com php-src: Fixed bug #69534 (Cycle leaks through declared properties on internal classes): Zend/tests/bug69534.phpt Zend/zend_gc.c Zend/zend_object_handlers.c |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-86630@lists.php.net to get a copy of this message | ||
Commit: 2a9f9860d724296e4853515c04dea3dcb729654d
Author: Dmitry Stogov <dmitry@zend.com> Wed, 6 May 2015 21:33:49 +0300
Parents: ab97606b8a9501599cf027b13b72fc0c92e3a16e
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=2a9f9860d724296e4853515c04dea3dcb729654d
Log:
Fixed bug #69534 (Cycle leaks through declared properties on internal classes)
Bugs:
https://bugs.php.net/69534
Changed paths:
A Zend/tests/bug69534.phpt
M Zend/zend_gc..c
M Zend/zend_object_handlers.c
Diff:
diff --git a/Zend/tests/bug69534.phpt b/Zend/tests/bug69534.phpt
new file mode 100644
index 0000000..1f02754
--- /dev/null
+++ b/Zend/tests/bug69534.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #69534 (Cycle leaks through declared properties on internal classes)
+--FILE--
+<?php
+class Node extends SplObjectStorage {
+ public $prop;
+}
+
+$node1 = new Node;
+$node2 = new Node;
+$node1->prop = $node2;
+$node2->prop = $node1;
+unset($node1);
+unset($node2);
+var_dump(gc_collect_cycles());
+?>
+--EXPECT--
+int(2)
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c
index 30d75c2..dc5a458 100644
--- a/Zend/zend_gc.c
+++ b/Zend/zend_gc.c
@@ -295,6 +295,7 @@ static void gc_scan_black(zend_refcounted *ref)
{
HashTable *ht;
Bucket *p, *end;
+ zval *zv;
tail_call:
ht = NULL;
@@ -362,12 +363,24 @@ tail_call:
if (!ht->nNumUsed) return;
p = ht->arData;
end = p + ht->nNumUsed;
- while (!Z_REFCOUNTED((--end)->val)) {
+ while (1) {
+ end--;
+ zv = &end->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ break;
+ }
if (p == end) return;
}
while (p != end) {
- if (Z_REFCOUNTED(p->val)) {
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ ref = Z_COUNTED_P(zv);
GC_REFCOUNT(ref)++;
if (GC_REF_GET_COLOR(ref) != GC_BLACK) {
gc_scan_black(ref);
@@ -375,7 +388,11 @@ tail_call:
}
p++;
}
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ ref = Z_COUNTED_P(zv);
GC_REFCOUNT(ref)++;
if (GC_REF_GET_COLOR(ref) != GC_BLACK) {
goto tail_call;
@@ -386,6 +403,7 @@ static void gc_mark_grey(zend_refcounted *ref)
{
HashTable *ht;
Bucket *p, *end;
+ zval *zv;
tail_call:
if (GC_REF_GET_COLOR(ref) != GC_GREY) {
@@ -454,27 +472,43 @@ tail_call:
if (!ht->nNumUsed) return;
p = ht->arData;
end = p + ht->nNumUsed;
- while (!Z_REFCOUNTED((--end)->val)) {
+ while (1) {
+ end--;
+ zv = &end->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ break;
+ }
if (p == end) return;
}
while (p != end) {
- if (Z_REFCOUNTED(p->val)) {
- if (Z_TYPE(p->val) == IS_OBJECT &&
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ if (Z_TYPE_P(zv) == IS_OBJECT &&
UNEXPECTED(!EG(objects_store).object_buckets)) {
- Z_TYPE_INFO(p->val) = IS_NULL;
+ Z_TYPE_INFO_P(zv) = IS_NULL;
} else {
- ref = Z_COUNTED(p->val);
+ ref = Z_COUNTED_P(zv);
GC_REFCOUNT(ref)--;
gc_mark_grey(ref);
}
}
p++;
}
- if (Z_TYPE(p->val) == IS_OBJECT &&
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_TYPE_P(zv) == IS_OBJECT &&
UNEXPECTED(!EG(objects_store).object_buckets)) {
- Z_TYPE_INFO(p->val) = IS_NULL;
+ Z_TYPE_INFO_P(zv) = IS_NULL;
} else {
- ref = Z_COUNTED(p->val);
+ ref = Z_COUNTED_P(zv);
GC_REFCOUNT(ref)--;
goto tail_call;
}
@@ -497,6 +531,7 @@ static void gc_scan(zend_refcounted *ref)
{
HashTable *ht;
Bucket *p, *end;
+ zval *zv;
tail_call:
if (GC_REF_GET_COLOR(ref) == GC_GREY) {
@@ -557,17 +592,33 @@ tail_call:
if (!ht->nNumUsed) return;
p = ht->arData;
end = p + ht->nNumUsed;
- while (!Z_REFCOUNTED((--end)->val)) {
+ while (1) {
+ end--;
+ zv = &end->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ break;
+ }
if (p == end) return;
}
while (p != end) {
- if (Z_REFCOUNTED(p->val)) {
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ ref = Z_COUNTED_P(zv);
gc_scan(ref);
}
p++;
}
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ ref = Z_COUNTED_P(zv);
goto tail_call;
}
}
@@ -641,6 +692,7 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_additional
int count = 0;
HashTable *ht;
Bucket *p, *end;
+ zval *zv;
tail_call:
if (GC_REF_GET_COLOR(ref) == GC_WHITE) {
@@ -731,25 +783,41 @@ tail_call:
if (!ht->nNumUsed) return count;
p = ht->arData;
end = p + ht->nNumUsed;
- while (!Z_REFCOUNTED((--end)->val)) {
+ while (1) {
+ end--;
+ zv = &end->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ break;
+ }
/* count non-refcounted for compatibility ??? */
- if (Z_TYPE(end->val) != IS_UNDEF && Z_TYPE(end->val) != IS_INDIRECT) {
+ if (Z_TYPE_P(zv) != IS_UNDEF) {
count++;
}
- if (p == end) return count;
+ if (p == end) return;
}
while (p != end) {
- if (Z_REFCOUNTED(p->val)) {
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ ref = Z_COUNTED_P(zv);
GC_REFCOUNT(ref)++;
count += gc_collect_white(ref, flags, additional_buffer);
/* count non-refcounted for compatibility ??? */
- } else if (Z_TYPE(p->val) != IS_UNDEF && Z_TYPE(p->val) != IS_INDIRECT) {
- count++;
+ } else if (Z_TYPE_P(zv) != IS_UNDEF) {
+ count++;
}
p++;
}
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ ref = Z_COUNTED_P(zv);
GC_REFCOUNT(ref)++;
goto tail_call;
}
@@ -806,6 +874,7 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buff
{
HashTable *ht = NULL;
Bucket *p, *end;
+ zval *zv;
tail_call:
if (root ||
@@ -870,17 +939,33 @@ tail_call:
if (!ht->nNumUsed) return;
p = ht->arData;
end = p + ht->nNumUsed;
- while (!Z_REFCOUNTED((--end)->val)) {
+ while (1) {
+ end--;
+ zv = &end->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ break;
+ }
if (p == end) return;
}
while (p != end) {
- if (Z_REFCOUNTED(p->val)) {
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ ref = Z_COUNTED_P(zv);
gc_remove_nested_data_from_buffer(ref, NULL);
}
p++;
}
- ref = Z_COUNTED(p->val);
+ zv = &p->val;
+ if (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ ref = Z_COUNTED_P(zv);
goto tail_call;
}
}
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index b85dd84..363ea13 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -127,9 +127,15 @@ ZEND_API HashTable *zend_std_get_gc(zval *object, zval **table, int *n) /* {{{
*
} else {
zend_object *zobj = Z_OBJ_P(object);
- *table = zobj->properties_table;
- *n = zobj->ce->default_properties_count;
- return zobj->properties;
+ if (zobj->properties) {
+ *table = NULL;
+ *n = 0;
+ return zobj->properties;
+ } else {
+ *table = zobj->properties_table;
+ *n = zobj->ce->default_properties_count;
+ return NULL;
+ }
}
}
/* }}} */