dmitry Mon, 14 Feb 2011 10:52:16 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=308320
Log: Fixed Bug #53958 (Closures can't 'use' shared variables by value and by reference) Bug: http://bugs.php.net/53958 (Assigned) Closures can't 'use' shared variables by value and by reference Changed paths: U php/php-src/branches/PHP_5_3/NEWS A php/php-src/branches/PHP_5_3/Zend/tests/bug53958.phpt U php/php-src/branches/PHP_5_3/Zend/zend_closures.c A php/php-src/trunk/Zend/tests/bug53958.phpt U php/php-src/trunk/Zend/zend_variables.c Modified: php/php-src/branches/PHP_5_3/NEWS =================================================================== --- php/php-src/branches/PHP_5_3/NEWS 2011-02-14 10:10:52 UTC (rev 308319) +++ php/php-src/branches/PHP_5_3/NEWS 2011-02-14 10:52:16 UTC (rev 308320) @@ -10,6 +10,8 @@ . Added options to debug backtrace functions. (Stas) . Fixed Bug #53971 (isset() and empty() produce apparently spurious runtime error). (Dmitry) + . Fixed Bug #53958 (Closures can't 'use' shared variables by value and by + reference). (Dmitry) . Fixed Bug #53629 (memory leak inside highlight_string()). (Hannes, Ilia) . Fixed Bug #51458 (Lack of error context with nested exceptions). (Stas) . Fixed Bug #47143 (Throwing an exception in a destructor causes a fatal Added: php/php-src/branches/PHP_5_3/Zend/tests/bug53958.phpt =================================================================== --- php/php-src/branches/PHP_5_3/Zend/tests/bug53958.phpt (rev 0) +++ php/php-src/branches/PHP_5_3/Zend/tests/bug53958.phpt 2011-02-14 10:52:16 UTC (rev 308320) @@ -0,0 +1,61 @@ +--TEST-- +Bug #53958 (Closures can't 'use' shared variables by value and by reference) +--FILE-- +<?php +// TEST 1 +$a = 1; +$fn1 = function() use ($a) {echo "$a\n"; $a++;}; +$fn2 = function() use ($a) {echo "$a\n"; $a++;}; +$a = 5; +$fn1(); // 1 +$fn2(); // 1 +$fn1(); // 1 +$fn2(); // 1 + +// TEST 2 +$b = 1; +$fn1 = function() use (&$b) {echo "$b\n"; $b++;}; +$fn2 = function() use (&$b) {echo "$b\n"; $b++;}; +$b = 5; +$fn1(); // 5 +$fn2(); // 6 +$fn1(); // 7 +$fn2(); // 8 + +// TEST 3 +$c = 1; +$fn1 = function() use (&$c) {echo "$c\n"; $c++;}; +$fn2 = function() use ($c) {echo "$c\n"; $c++;}; +$c = 5; +$fn1(); // 5 +$fn2(); // 1 +$fn1(); // 6 +$fn2(); // 1 + +// TEST 4 +$d = 1; +$fn1 = function() use ($d) {echo "$d\n"; $d++;}; +$fn2 = function() use (&$d) {echo "$d\n"; $d++;}; +$d = 5; +$fn1(); // 1 +$fn2(); // 5 +$fn1(); // 1 +$fn2(); // 6 +?> +--EXPECT-- +1 +1 +1 +1 +5 +6 +7 +8 +5 +1 +6 +1 +1 +5 +1 +6 Modified: php/php-src/branches/PHP_5_3/Zend/zend_closures.c =================================================================== --- php/php-src/branches/PHP_5_3/Zend/zend_closures.c 2011-02-14 10:10:52 UTC (rev 308319) +++ php/php-src/branches/PHP_5_3/Zend/zend_closures.c 2011-02-14 10:52:16 UTC (rev 308320) @@ -323,6 +323,7 @@ { HashTable *target = va_arg(args, HashTable*); zend_bool is_ref; + zval *tmp; if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) { is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF; @@ -332,25 +333,31 @@ } if (zend_hash_quick_find(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, (void **) &p) == FAILURE) { if (is_ref) { - zval *tmp; - ALLOC_INIT_ZVAL(tmp); Z_SET_ISREF_P(tmp); zend_hash_quick_add(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), (void**)&p); } else { - p = &EG(uninitialized_zval_ptr); + tmp = EG(uninitialized_zval_ptr); zend_error(E_NOTICE,"Undefined variable: %s", key->arKey); } } else { if (is_ref) { SEPARATE_ZVAL_TO_MAKE_IS_REF(p); + tmp = *p; } else if (Z_ISREF_PP(p)) { - SEPARATE_ZVAL(p); + ALLOC_INIT_ZVAL(tmp); + *tmp = **p; + Z_SET_REFCOUNT_P(tmp, 0); + Z_UNSET_ISREF_P(tmp); + } else { + tmp = *p; } } + } else { + tmp = *p; } - if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, p, sizeof(zval*), NULL) == SUCCESS) { - Z_ADDREF_PP(p); + if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), NULL) == SUCCESS) { + Z_ADDREF_P(tmp); } return ZEND_HASH_APPLY_KEEP; } Added: php/php-src/trunk/Zend/tests/bug53958.phpt =================================================================== --- php/php-src/trunk/Zend/tests/bug53958.phpt (rev 0) +++ php/php-src/trunk/Zend/tests/bug53958.phpt 2011-02-14 10:52:16 UTC (rev 308320) @@ -0,0 +1,61 @@ +--TEST-- +Bug #53958 (Closures can't 'use' shared variables by value and by reference) +--FILE-- +<?php +// TEST 1 +$a = 1; +$fn1 = function() use ($a) {echo "$a\n"; $a++;}; +$fn2 = function() use ($a) {echo "$a\n"; $a++;}; +$a = 5; +$fn1(); // 1 +$fn2(); // 1 +$fn1(); // 1 +$fn2(); // 1 + +// TEST 2 +$b = 1; +$fn1 = function() use (&$b) {echo "$b\n"; $b++;}; +$fn2 = function() use (&$b) {echo "$b\n"; $b++;}; +$b = 5; +$fn1(); // 5 +$fn2(); // 6 +$fn1(); // 7 +$fn2(); // 8 + +// TEST 3 +$c = 1; +$fn1 = function() use (&$c) {echo "$c\n"; $c++;}; +$fn2 = function() use ($c) {echo "$c\n"; $c++;}; +$c = 5; +$fn1(); // 5 +$fn2(); // 1 +$fn1(); // 6 +$fn2(); // 1 + +// TEST 4 +$d = 1; +$fn1 = function() use ($d) {echo "$d\n"; $d++;}; +$fn2 = function() use (&$d) {echo "$d\n"; $d++;}; +$d = 5; +$fn1(); // 1 +$fn2(); // 5 +$fn1(); // 1 +$fn2(); // 6 +?> +--EXPECT-- +1 +1 +1 +1 +5 +6 +7 +8 +5 +1 +6 +1 +1 +5 +1 +6 Modified: php/php-src/trunk/Zend/zend_variables.c =================================================================== --- php/php-src/trunk/Zend/zend_variables.c 2011-02-14 10:10:52 UTC (rev 308319) +++ php/php-src/trunk/Zend/zend_variables.c 2011-02-14 10:52:16 UTC (rev 308320) @@ -192,6 +192,7 @@ { HashTable *target = va_arg(args, HashTable*); zend_bool is_ref; + zval *tmp; if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) { is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF; @@ -200,26 +201,32 @@ zend_rebuild_symbol_table(TSRMLS_C); } if (zend_hash_quick_find(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, (void **) &p) == FAILURE) { - if (is_ref) { - zval *tmp; - + if (is_ref) { ALLOC_INIT_ZVAL(tmp); Z_SET_ISREF_P(tmp); zend_hash_quick_add(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), (void**)&p); } else { - p = &EG(uninitialized_zval_ptr); + tmp = EG(uninitialized_zval_ptr); zend_error(E_NOTICE,"Undefined variable: %s", key->arKey); } } else { if (is_ref) { SEPARATE_ZVAL_TO_MAKE_IS_REF(p); + tmp = *p; } else if (Z_ISREF_PP(p)) { - SEPARATE_ZVAL(p); + ALLOC_INIT_ZVAL(tmp); + ZVAL_COPY_VALUE(tmp, *p); + Z_SET_REFCOUNT_P(tmp, 0); + Z_UNSET_ISREF_P(tmp); + } else { + tmp = *p; } } + } else { + tmp = *p; } - if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, p, sizeof(zval*), NULL) == SUCCESS) { - Z_ADDREF_PP(p); + if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), NULL) == SUCCESS) { + Z_ADDREF_P(tmp); } return ZEND_HASH_APPLY_KEEP; }
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
