Skip to content

Commit 6b68f44

Browse files
committed
Fix bug #64979: Wrong behavior of static variables in closure generators
1 parent 1d1fb69 commit 6b68f44

File tree

3 files changed

+39
-11
lines changed

3 files changed

+39
-11
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? 2013, PHP 5.5.5
44

5+
- Core:
6+
. Fixed bug #64979 (Wrong behavior of static variables in closure generators).
7+
(Nikita)
8+
59
- CLI server:
610
. Fixed bug #65633 (built-in server treat some http headers as
711
case-sensitive). (Adam)

Zend/tests/bug64979.phpt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
--TEST--
2-
Bug #64578 (Closures with static variables can be generators)
3-
--XFAIL--
4-
Bug #64979 not fixed yet.
2+
Bug #64979 (Wrong behavior of static variables in closure generators)
53
--FILE--
64
<?php
75

86
function new_closure_gen() {
9-
return function() {
10-
static $foo = 0;
11-
yield ++$foo;
12-
};
7+
return function() {
8+
static $foo = 0;
9+
yield ++$foo;
10+
};
1311
}
1412

1513
$closure1 = new_closure_gen();
@@ -20,9 +18,9 @@ $gen2 = $closure1();
2018
$gen3 = $closure2();
2119

2220
foreach (array($gen1, $gen2, $gen3) as $gen) {
23-
foreach ($gen as $val) {
24-
print "$val\n";
25-
}
21+
foreach ($gen as $val) {
22+
var_dump($val);
23+
}
2624
}
2725

2826
?>

Zend/zend_generators.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,16 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
226226
}
227227
/* }}} */
228228

229+
static void copy_closure_static_var(zval **var TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
230+
{
231+
HashTable *target = va_arg(args, HashTable *);
232+
233+
SEPARATE_ZVAL_TO_MAKE_IS_REF(var);
234+
Z_ADDREF_PP(var);
235+
zend_hash_quick_update(target, key->arKey, key->nKeyLength, key->h, var, sizeof(zval *), NULL);
236+
}
237+
/* }}} */
238+
229239
/* Requires globals EG(scope), EG(current_scope), EG(This),
230240
* EG(active_symbol_table) and EG(current_execute_data). */
231241
ZEND_API zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
@@ -242,7 +252,23 @@ ZEND_API zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /*
242252
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
243253
zend_op_array *op_array_copy = (zend_op_array*)emalloc(sizeof(zend_op_array));
244254
*op_array_copy = *op_array;
245-
function_add_ref((zend_function *) op_array_copy);
255+
256+
(*op_array->refcount)++;
257+
op_array->run_time_cache = NULL;
258+
if (op_array->static_variables) {
259+
ALLOC_HASHTABLE(op_array_copy->static_variables);
260+
zend_hash_init(
261+
op_array_copy->static_variables,
262+
zend_hash_num_elements(op_array->static_variables),
263+
NULL, ZVAL_PTR_DTOR, 0
264+
);
265+
zend_hash_apply_with_arguments(
266+
op_array->static_variables TSRMLS_CC,
267+
(apply_func_args_t) copy_closure_static_var,
268+
1, op_array_copy->static_variables
269+
);
270+
}
271+
246272
op_array = op_array_copy;
247273
}
248274

0 commit comments

Comments
 (0)