summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2013-02-01 18:33:26 +0100
committerNikita Popov <nikic@php.net>2013-02-01 18:33:26 +0100
commit3ee20e450fb5e52f68174f982fbd4f13eb2d9beb (patch)
tree63d111ce7070a54804a95df18868b2d5259c129f
parentac18c318dc4af08074a56cf706678a2457495944 (diff)
downloadphp-git-3ee20e450fb5e52f68174f982fbd4f13eb2d9beb.tar.gz
Fix segfault when cloning generator with properties
Rule of thumb: Always implement the object clone handler rather than the object storage clone handler. Actually I think we should drop the latter. It's nearly never usable.
-rw-r--r--Zend/tests/generators/clone_with_properties.phpt18
-rw-r--r--Zend/zend_generators.c26
2 files changed, 37 insertions, 7 deletions
diff --git a/Zend/tests/generators/clone_with_properties.phpt b/Zend/tests/generators/clone_with_properties.phpt
new file mode 100644
index 0000000000..900253c682
--- /dev/null
+++ b/Zend/tests/generators/clone_with_properties.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Tests cloning a generator with properties
+--FILE--
+<?php
+
+function gen() { yield; }
+
+$g1 = gen();
+$g1->prop = 'val';
+
+$g2 = clone $g1;
+unset($g1);
+
+var_dump($g2->prop);
+
+?>
+--EXPECT--
+string(3) "val"
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index e8787d5e0d..621320614c 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -27,6 +27,8 @@
ZEND_API zend_class_entry *zend_ce_generator;
static zend_object_handlers zend_generator_handlers;
+static zend_object_value zend_generator_create(zend_class_entry *class_type TSRMLS_DC);
+
ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution TSRMLS_DC) /* {{{ */
{
if (generator->value) {
@@ -188,10 +190,19 @@ static void zend_generator_free_storage(zend_generator *generator TSRMLS_DC) /*
}
/* }}} */
-static void zend_generator_clone_storage(zend_generator *orig, zend_generator **clone_ptr TSRMLS_DC) /* {{{ */
+static zend_object_value zend_generator_clone(zval *object TSRMLS_DC) /* {{{ */
{
- zend_generator *clone = emalloc(sizeof(zend_generator));
- memcpy(clone, orig, sizeof(zend_generator));
+ zend_generator *orig = zend_object_store_get_object(object TSRMLS_CC);
+ zend_object_value clone_val = zend_generator_create(Z_OBJCE_P(object) TSRMLS_CC);
+ zend_generator *clone = zend_object_store_get_object_by_handle(clone_val.handle TSRMLS_CC);
+
+ zend_objects_clone_members(
+ &clone->std, clone_val, &orig->std, Z_OBJ_HANDLE_P(object) TSRMLS_CC
+ );
+
+ clone->execute_data = orig->execute_data;
+ clone->largest_used_integer_key = orig->largest_used_integer_key;
+ clone->flags = orig->flags;
if (orig->execute_data) {
/* Create a few shorter aliases to the old execution data */
@@ -335,14 +346,16 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
/* The value and key are known not to be references, so simply add refs */
if (orig->value) {
+ clone->value = orig->value;
Z_ADDREF_P(orig->value);
}
if (orig->key) {
+ clone->key = orig->key;
Z_ADDREF_P(orig->key);
}
- *clone_ptr = clone;
+ return clone_val;
}
/* }}} */
@@ -362,8 +375,7 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
object.handle = zend_objects_store_put(generator,
(zend_objects_store_dtor_t) zend_generator_dtor_storage,
(zend_objects_free_object_storage_t) zend_generator_free_storage,
- (zend_objects_store_clone_t) zend_generator_clone_storage
- TSRMLS_CC
+ NULL TSRMLS_CC
);
object.handlers = &zend_generator_handlers;
@@ -863,7 +875,7 @@ void zend_register_generator_ce(TSRMLS_D) /* {{{ */
memcpy(&zend_generator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
zend_generator_handlers.get_constructor = zend_generator_get_constructor;
- zend_generator_handlers.clone_obj = zend_objects_store_clone_obj;
+ zend_generator_handlers.clone_obj = zend_generator_clone;
}
/* }}} */