com php-src: Fix bug 666222: NEWS Zend/tests/closure_bug6 6622.phpt Zend/zend_closures.c Zend/zend_vm _def.h Zend/zend_vm_execute.h
| From: | Stanislav Malyshev | Date: | Mon, 09 Jun 2014 01:59:23 +0000 |
| Subject: | com php-src: Fix bug 666222: NEWS Zend/tests/closure_bug6 6622.phpt Zend/zend_closures.c Zend/zend_vm _def.h Zend/zend_vm_execute.h | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-78749@lists.php.net to get a copy of this message | ||
Commit: e030efa4f64b377acc5311a92b00a8576643bb11
Author: Levi Morrison <levim@php.net> Mon, 12 May 2014 21:53:08 -0600
Committer: Stanislav Malyshev <stas@php.net> Sun, 8 Jun 2014 18:59:23 -0700
Parents: 33926b19d09d54ee43854eb59a987cd812179a7f
Branches: PHP-5.4 PHP-5.5 PHP-5.6 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=e030efa4f64b377acc5311a92b00a8576643bb11
Log:
Fix bug 666222
This also adds some smaller, isolated tests related to bug 66622..
Conflicts:
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Bugs:
https://bugs.php.net/666222
https://bugs.php.net/66622
Changed paths:
M NEWS
A Zend/tests/closure_bug66622.phpt
M Zend/zend_closures.c
M Zend/zend_vm_def.h
M Zend/zend_vm_execute.h
Diff:
diff --git a/NEWS b/NEWS
index 7354aa9..65e2fad 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@ PHP NEWS
. Fixed BC break introduced by patch for bug #67072. (Anatol)
. Fixed bug #67390 (insecure temporary file use in the configure script).
(Remi) (CVE-2014-3981)
+ . Fixed bug #66622 (Closures do not correctly capture the late bound class
+ (static::) in some cases). (Levi Morrison)
- Date:
. Fixed bug #67308 (Serialize of DateTime truncates fractions of second).
diff --git a/Zend/tests/closure_bug66622.phpt b/Zend/tests/closure_bug66622.phpt
new file mode 100644
index 0000000..1c9577d
--- /dev/null
+++ b/Zend/tests/closure_bug66622.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Bug 66622: Closures do not correctly capture the late bound class (static::) in some cases
+
+--FILE--
+<?php
+class A {
+ static function name() { return 'A'; }
+ function foo() {
+ $fn = function() { return static::name(); };
+ echo static::name() . ' vs ' . $fn() . "\n";
+ }
+ function bar() {
+ $fn = static function() { return static::name(); };
+ echo static::name() . ' vs ' . $fn() . "\n";
+ }
+ static function baz() {
+ $fn = function() { return static::name(); };
+ echo static::name() . ' vs ' . $fn() . "\n";
+ }
+}
+class B extends A {
+ static function name() { return 'B'; }
+}
+
+function test() {
+ (new B)->foo();
+ (new B)->bar();
+ (new B)->baz();
+ B::baz();
+}
+test();
+
+--EXPECT--
+B vs B
+B vs B
+B vs B
+B vs B
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index c18972a..9ae82b4 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -487,6 +487,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
}
}
+ closure->this_ptr = NULL;
/* Invariants:
* If the closure is unscoped, it has no bound object.
* The the closure is scoped, it's either static or it's bound */
@@ -498,10 +499,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func,
zend_class_ent
Z_ADDREF_P(this_ptr);
} else {
closure->func.common.fn_flags |= ZEND_ACC_STATIC;
- closure->this_ptr = NULL;
}
- } else {
- closure->this_ptr = NULL;
}
}
/* }}} */
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index ab33468..a7ad3aa 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5161,6 +5161,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
{
USE_OPLINE
zend_function *op_array;
+ int closure_is_static, closure_is_being_defined_inside_static_context;
SAVE_OPLINE();
@@ -5169,7 +5170,13 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
}
- zend_create_closure(&EX_T(opline->result..var).tmp_var, op_array, EG(scope), EG(This)
TSRMLS_CC);
+ closure_is_static = op_array->common.fn_flags & ZEND_ACC_STATIC;
+ closure_is_being_defined_inside_static_context = EX(prev_execute_data) &&
EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC;
+ if (closure_is_static || closure_is_being_defined_inside_static_context) {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array,
EG(called_scope), NULL TSRMLS_CC);
+ } else {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array,
EG(scope), EG(This) TSRMLS_CC);
+ }
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index fa997b2..fba5f9c 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -5847,6 +5847,7 @@ static int ZEND_FASTCALL
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER
{
USE_OPLINE
zend_function *op_array;
+ int closure_is_static, closure_is_being_defined_inside_static_context;
SAVE_OPLINE();
@@ -5855,7 +5856,13 @@ static int ZEND_FASTCALL
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER
zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
}
- zend_create_closure(&EX_T(opline->result.var).tmp_var, op_array, EG(scope), EG(This)
TSRMLS_CC);
+ closure_is_static = op_array->common.fn_flags & ZEND_ACC_STATIC;
+ closure_is_being_defined_inside_static_context = EX(prev_execute_data) &&
EX(prev_execute_data)->function_state.function->common..fn_flags & ZEND_ACC_STATIC;
+ if (closure_is_static || closure_is_being_defined_inside_static_context) {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array,
EG(called_scope), NULL TSRMLS_CC);
+ } else {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array,
EG(scope), EG(This) TSRMLS_CC);
+ }
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();