From: Dmitry Stogov Date: Wed, 20 Apr 2011 12:59:18 +0000 (+0000) Subject: Fixed bug #54367 (Use of closure causes problem in ArrayAccess). X-Git-Tag: php-5.3.7RC1~174 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c157f4b4e666077431f6638809735f4740a82681;p=php Fixed bug #54367 (Use of closure causes problem in ArrayAccess). --- diff --git a/NEWS b/NEWS index 39996374bc..4c2b338248 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ PHP NEWS . 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). diff --git a/Zend/tests/bug54367.phpt b/Zend/tests/bug54367.phpt new file mode 100644 index 0000000000..1ca6ad4252 --- /dev/null +++ b/Zend/tests/bug54367.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #54367 (Use of closure causes problem in ArrayAccess) +--FILE-- + +--EXPECT-- +string(1) "p" +string(3) "foo" diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index fa26f6efaa..faa3b7705c 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -373,6 +373,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func TSRMLS_DC) /* { 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) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2ffd0a754f..5f2ebff151 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2087,14 +2087,20 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } 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 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } } + 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); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7e377902b8..888ba953da 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -163,6 +163,10 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) } } + 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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } 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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } 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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } 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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } 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(); }