diff options
| author | Bob Weinand <bobwei9@hotmail.com> | 2015-04-15 21:41:29 +0200 | 
|---|---|---|
| committer | Bob Weinand <bobwei9@hotmail.com> | 2015-04-15 21:42:27 +0200 | 
| commit | 4e76d58b2b1614125ed232450197a9c23aa5cc43 (patch) | |
| tree | 6660bf0acfe3d07abb271db4fa6ba0de1e8d82a2 /Zend/zend_generators.c | |
| parent | 27033f981816a09fb63c258494af7e91f16a9736 (diff) | |
| download | php-git-4e76d58b2b1614125ed232450197a9c23aa5cc43.tar.gz | |
Fix object leak for yield from (added proper refcounting)
Diffstat (limited to 'Zend/zend_generators.c')
| -rw-r--r-- | Zend/zend_generators.c | 37 | 
1 files changed, 33 insertions, 4 deletions
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 8976a0fcc4..98603200bf 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -186,6 +186,8 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */  }  /* }}} */ +static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf); +  static void zend_generator_free_storage(zend_object *object) /* {{{ */  {  	zend_generator *generator = (zend_generator*) object; @@ -205,6 +207,15 @@ static void zend_generator_free_storage(zend_object *object) /* {{{ */  	if (generator->iterator) {  		zend_iterator_dtor(generator->iterator);  	} + +	if (generator->node.children == 0) { +		zend_generator *root = generator->node.ptr.root, *next; +		while (root != generator) { +			next = zend_generator_get_child(&root->node, generator); +			OBJ_RELEASE(&root->std); +			root = next; +		} +	}  }  /* }}} */ @@ -387,6 +398,7 @@ static void zend_generator_merge_child_nodes(zend_generator_node *dest, zend_gen  	}  } +/* Make attention so that the root of each subtree of the Generators tree is referenced once per leaf */  static void zend_generator_add_child(zend_generator *generator, zend_generator *child)  {  	zend_generator *leaf = child->node.children ? child->node.ptr.leaf : child; @@ -396,6 +408,7 @@ static void zend_generator_add_child(zend_generator *generator, zend_generator *  	if (was_leaf) {  		zend_generator *next = generator->node.parent;  		leaf->node.ptr.root = generator->node.ptr.root; +		++GC_REFCOUNT(&generator->std); /* we need to increment the generator refcount here as it became integrated into the tree (no leaf), but we must not increment the refcount of the *whole* path in tree */  		generator->node.ptr.leaf = leaf;  		while (next) { @@ -472,12 +485,14 @@ void zend_generator_yield_from(zend_generator *this, zend_generator *from)  	zend_generator_add_child(from, this);  	this->node.parent = from; +	zend_generator_get_current(this); +	--GC_REFCOUNT(from);  }  ZEND_API zend_generator *zend_generator_get_current(zend_generator *generator)  {  	zend_generator *leaf; -	zend_generator *root; +	zend_generator *root, *old_root;  	if (generator->node.parent == NULL) {  		/* we're not in yield from mode */ @@ -492,8 +507,18 @@ ZEND_API zend_generator *zend_generator_get_current(zend_generator *generator)  		return root;  	} +	/* generator at the root had stopped */ +	if (root != generator) { +		old_root = root; +		root = zend_generator_get_child(&root->node, leaf); +	} else { +		old_root = NULL; +	} +  	while (!root->execute_data && root != generator) { -		/* generator at the root had stopped */ +		OBJ_RELEASE(&old_root->std); +		old_root = root; +  		root = zend_generator_get_child(&root->node, leaf);  	} @@ -528,10 +553,15 @@ ZEND_API zend_generator *zend_generator_get_current(zend_generator *generator)  		} else {  			do {  				root = root->node.parent; +				++GC_REFCOUNT(&root->std);  			} while (root->node.parent);  		}  	} +	if (old_root) { +		OBJ_RELEASE(&old_root->std); +	} +  	return leaf->node.ptr.root = root;  } @@ -693,9 +723,8 @@ try_again:  		 * In case we did yield from, the Exception must be rethrown into  		 * its calling frame (see above in if (check_yield_from). */  		if (UNEXPECTED(EG(exception) != NULL)) { -			zend_generator_close(generator, 0); -  			if (generator == orig_generator) { +				zend_generator_close(generator, 0);  				zend_throw_exception_internal(NULL);  			} else {  				generator = zend_generator_get_current(orig_generator);  | 
