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

Reply via email to