Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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

  • Loading branch information...
commit 821d7169d9d575ceef71e69570b98519826ccb01 1 parent 11941b3
Dmitry Stogov authored
View
24 Zend/tests/bug54367.phpt
@@ -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"
View
1  Zend/zend_closures.c
@@ -407,6 +407,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
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) {
View
14 Zend/zend_vm_def.h
@@ -2370,14 +2370,20 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
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 @@ 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);
View
40 Zend/zend_vm_execute.h
@@ -471,6 +471,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);
@@ -1224,14 +1228,20 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H
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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H
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 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
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 {
Please sign in to comment.
Something went wrong with that request. Please try again.