dmitry                                   Wed, 20 Apr 2011 12:59:18 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=310389

Log:
Fixed bug #54367 (Use of closure causes problem in ArrayAccess).

Bug: http://bugs.php.net/54367 (Assigned) Use of closure causes problem in 
ArrayAccess
      
Changed paths:
    U   php/php-src/branches/PHP_5_3/NEWS
    A   php/php-src/branches/PHP_5_3/Zend/tests/bug54367.phpt
    U   php/php-src/branches/PHP_5_3/Zend/zend_closures.c
    U   php/php-src/branches/PHP_5_3/Zend/zend_vm_def.h
    U   php/php-src/branches/PHP_5_3/Zend/zend_vm_execute.h
    A   php/php-src/trunk/Zend/tests/bug54367.phpt
    U   php/php-src/trunk/Zend/zend_closures.c
    U   php/php-src/trunk/Zend/zend_vm_def.h
    U   php/php-src/trunk/Zend/zend_vm_execute.h

Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/branches/PHP_5_3/NEWS	2011-04-20 12:59:18 UTC (rev 310389)
@@ -7,6 +7,7 @@
   . Fixed bug #54372 (Crash accessing global object itself returned from its
     __get() handle). (Dmitry)
   . Fixed bug #54358 (Closure, use and reference). (Dmitry)
+  . Fixed bug #54367 (Use of closure causes problem in ArrayAccess). (Dmitry)
   . Fixed bug #54039 (use() of static variables in lambda functions can break
      staticness). (Dmitry)
   . Fixed bug #54262 (Crash when assigning value to a dimension in a non-array).

Added: php/php-src/branches/PHP_5_3/Zend/tests/bug54367.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/tests/bug54367.phpt	                        (rev 0)
+++ php/php-src/branches/PHP_5_3/Zend/tests/bug54367.phpt	2011-04-20 12:59:18 UTC (rev 310389)
@@ -0,0 +1,24 @@
+--TEST--
+Bug #54367 (Use of closure causes problem in ArrayAccess)
+--FILE--
+<?php
+class MyObjet implements ArrayAccess
+{
+    public function offsetSet($offset, $value) { }
+    public function offsetExists($offset) {  }
+    public function offsetUnset($offset) { }
+
+    public function offsetGet ($offset)
+    {
+	return function ($var) use ($offset) { // here is the problem
+              var_dump($offset, $var);
+        };
+    }
+}
+
+$a = new MyObjet();
+echo $a['p']('foo');
+?>
+--EXPECT--
+string(1) "p"
+string(3) "foo"

Modified: php/php-src/branches/PHP_5_3/Zend/zend_closures.c
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/zend_closures.c	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/branches/PHP_5_3/Zend/zend_closures.c	2011-04-20 12:59:18 UTC (rev 310389)
@@ -373,6 +373,7 @@
 	closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);

 	closure->func = *func;
+	closure->func.common.prototype = NULL;

 	if (closure->func.type == ZEND_USER_FUNCTION) {
 		if (closure->func.op_array.static_variables) {

Modified: php/php-src/branches/PHP_5_3/Zend/zend_vm_def.h
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/zend_vm_def.h	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/branches/PHP_5_3/Zend/zend_vm_def.h	2011-04-20 12:59:18 UTC (rev 310389)
@@ -2087,14 +2087,20 @@
 	} else {
 		function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);

-		if (OP2_TYPE != IS_CONST &&
+		if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
 		    Z_TYPE_P(function_name) == IS_OBJECT &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
-			FREE_OP2();
+			if (OP2_TYPE == IS_VAR && OP2_FREE &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {
+				FREE_OP2();
+			}
 			ZEND_VM_NEXT_OPCODE();
 		}

@@ -2159,6 +2165,10 @@
 		}
 	}

+	if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
+		zval_ptr_dtor((zval**)&op_array->prototype);
+	}
+
 	nested = EX(nested);

 	zend_vm_stack_free(execute_data TSRMLS_CC);

Modified: php/php-src/branches/PHP_5_3/Zend/zend_vm_execute.h
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/zend_vm_execute.h	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/branches/PHP_5_3/Zend/zend_vm_execute.h	2011-04-20 12:59:18 UTC (rev 310389)
@@ -163,6 +163,10 @@
 		}
 	}

+	if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
+		zval_ptr_dtor((zval**)&op_array->prototype);
+	}
+
 	nested = EX(nested);

 	zend_vm_stack_free(execute_data TSRMLS_CC);
@@ -750,14 +754,20 @@
 	} else {
 		function_name = &opline->op2.u.constant;

-		if (IS_CONST != IS_CONST &&
+		if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR &&
 		    Z_TYPE_P(function_name) == IS_OBJECT &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
+			if (IS_CONST == IS_VAR && 0 &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {

+			}
 			ZEND_VM_NEXT_OPCODE();
 		}

@@ -944,14 +954,20 @@
 	} else {
 		function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);

-		if (IS_TMP_VAR != IS_CONST &&
+		if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR &&
 		    Z_TYPE_P(function_name) == IS_OBJECT &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
-			zval_dtor(free_op2.var);
+			if (IS_TMP_VAR == IS_VAR && 1 &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {
+				zval_dtor(free_op2.var);
+			}
 			ZEND_VM_NEXT_OPCODE();
 		}

@@ -1045,14 +1061,20 @@
 	} else {
 		function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);

-		if (IS_VAR != IS_CONST &&
+		if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR &&
 		    Z_TYPE_P(function_name) == IS_OBJECT &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
-			if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
+			if (IS_VAR == IS_VAR && (free_op2.var != NULL) &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {
+				if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
+			}
 			ZEND_VM_NEXT_OPCODE();
 		}

@@ -1169,14 +1191,20 @@
 	} else {
 		function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC);

-		if (IS_CV != IS_CONST &&
+		if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR &&
 		    Z_TYPE_P(function_name) == IS_OBJECT &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
+			if (IS_CV == IS_VAR && 0 &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {

+			}
 			ZEND_VM_NEXT_OPCODE();
 		}


Added: php/php-src/trunk/Zend/tests/bug54367.phpt
===================================================================
--- php/php-src/trunk/Zend/tests/bug54367.phpt	                        (rev 0)
+++ php/php-src/trunk/Zend/tests/bug54367.phpt	2011-04-20 12:59:18 UTC (rev 310389)
@@ -0,0 +1,24 @@
+--TEST--
+Bug #54367 (Use of closure causes problem in ArrayAccess)
+--FILE--
+<?php
+class MyObjet implements ArrayAccess
+{
+    public function offsetSet($offset, $value) { }
+    public function offsetExists($offset) {  }
+    public function offsetUnset($offset) { }
+
+    public function offsetGet ($offset)
+    {
+	return function ($var) use ($offset) { // here is the problem
+              var_dump($offset, $var);
+        };
+    }
+}
+
+$a = new MyObjet();
+echo $a['p']('foo');
+?>
+--EXPECT--
+string(1) "p"
+string(3) "foo"

Modified: php/php-src/trunk/Zend/zend_closures.c
===================================================================
--- php/php-src/trunk/Zend/zend_closures.c	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/trunk/Zend/zend_closures.c	2011-04-20 12:59:18 UTC (rev 310389)
@@ -407,6 +407,7 @@
 	closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);

 	closure->func = *func;
+	closure->func.common.prototype = NULL;

 	if (closure->func.type == ZEND_USER_FUNCTION) {
 		if (closure->func.op_array.static_variables) {

Modified: php/php-src/trunk/Zend/zend_vm_def.h
===================================================================
--- php/php-src/trunk/Zend/zend_vm_def.h	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/trunk/Zend/zend_vm_def.h	2011-04-20 12:59:18 UTC (rev 310389)
@@ -2370,14 +2370,20 @@
 			EX(object) = NULL;
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
-		} else if (OP2_TYPE != IS_CONST &&
+		} else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
 		    EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
-			FREE_OP2();
+			if (OP2_TYPE == IS_VAR && OP2_FREE &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {
+				FREE_OP2();
+			}
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
@@ -2431,6 +2437,10 @@
 		}
 	}

+	if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
+		zval_ptr_dtor((zval**)&op_array->prototype);
+	}
+
 	nested = EX(nested);

 	zend_vm_stack_free(execute_data TSRMLS_CC);

Modified: php/php-src/trunk/Zend/zend_vm_execute.h
===================================================================
--- php/php-src/trunk/Zend/zend_vm_execute.h	2011-04-20 11:23:56 UTC (rev 310388)
+++ php/php-src/trunk/Zend/zend_vm_execute.h	2011-04-20 12:59:18 UTC (rev 310389)
@@ -471,6 +471,10 @@
 		}
 	}

+	if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
+		zval_ptr_dtor((zval**)&op_array->prototype);
+	}
+
 	nested = EX(nested);

 	zend_vm_stack_free(execute_data TSRMLS_CC);
@@ -1224,14 +1228,20 @@
 			EX(object) = NULL;
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
-		} else if (IS_CONST != IS_CONST &&
+		} else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR &&
 		    EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
+			if (IS_CONST == IS_VAR && 0 &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {

+			}
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
@@ -1458,14 +1468,20 @@
 			EX(object) = NULL;
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
-		} else if (IS_TMP_VAR != IS_CONST &&
+		} else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR &&
 		    EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
-			zval_dtor(free_op2.var);
+			if (IS_TMP_VAR == IS_VAR && 1 &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {
+				zval_dtor(free_op2.var);
+			}
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
@@ -1554,14 +1570,20 @@
 			EX(object) = NULL;
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
-		} else if (IS_VAR != IS_CONST &&
+		} else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR &&
 		    EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
-			if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
+			if (IS_VAR == IS_VAR && (free_op2.var != NULL) &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {
+				if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
+			}
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
@@ -1683,14 +1705,20 @@
 			EX(object) = NULL;
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
-		} else if (IS_CV != IS_CONST &&
+		} else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR &&
 		    EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure) &&
 			Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
 			if (EX(object)) {
 				Z_ADDREF_P(EX(object));
 			}
+			if (IS_CV == IS_VAR && 0 &&
+			    EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
+				/* Delay closure destruction until its invocation */
+				EX(fbc)->common.prototype = (zend_function*)function_name;
+			} else {

+			}
 			CHECK_EXCEPTION();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to