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