]> granicus.if.org Git - php/commitdiff
Fixed bug #54367 (Use of closure causes problem in ArrayAccess).
authorDmitry Stogov <dmitry@php.net>
Wed, 20 Apr 2011 12:59:18 +0000 (12:59 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 20 Apr 2011 12:59:18 +0000 (12:59 +0000)
NEWS
Zend/tests/bug54367.phpt [new file with mode: 0644]
Zend/zend_closures.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index 39996374bc82d9d8714031304fb7770cec43420f..4c2b338248189eb632e2ffe0be8ab7eb1d8c1b7d 100644 (file)
--- 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 (file)
index 0000000..1ca6ad4
--- /dev/null
@@ -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"
index fa26f6efaa425c0a9008b55ead4f28104e88f831..faa3b7705cbc0956c6c09c7eb10d0af75430b9b6 100644 (file)
@@ -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) {
index 2ffd0a754fe32242aba5bbfc264a9f1d22824b4f..5f2ebff151c6767bd45c48775a7e44ad2188b4d3 100644 (file)
@@ -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);
index 7e377902b8be30195e8a3efa3b635186490182cd..888ba953dad70189bbae7fefdc1f1ce993f6cc62 100644 (file)
@@ -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();
                }