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