mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
Fixed bug #75079
This commit is contained in:
parent
089a3213ae
commit
2023346973
2
NEWS
2
NEWS
@ -9,6 +9,8 @@ PHP NEWS
|
||||
. Fixed bug #75799 (arg of get_defined_functions is optional). (carusogabriel)
|
||||
. Fixed bug #75396 (Exit inside generator finally results in fatal error).
|
||||
(Nikita)
|
||||
. Fixed bug #75079 (self keyword leads to incorrectly generated TypeError when
|
||||
in closure in trait). (Nikita)
|
||||
|
||||
- IMAP:
|
||||
. Fixed bug #75774 (imap_append HeapCorruction). (Anatol)
|
||||
|
39
Zend/tests/bug75079.phpt
Normal file
39
Zend/tests/bug75079.phpt
Normal file
@ -0,0 +1,39 @@
|
||||
--TEST--
|
||||
Bug #75079: self keyword leads to incorrectly generated TypeError when in closure in trait
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
trait Foo
|
||||
{
|
||||
public function selfDo(self ...$Selfs)
|
||||
{
|
||||
array_map(
|
||||
function (self $Self) : self
|
||||
{
|
||||
return $Self;
|
||||
},
|
||||
$Selfs
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Bar
|
||||
{
|
||||
use Foo;
|
||||
}
|
||||
|
||||
class Baz
|
||||
{
|
||||
use Foo;
|
||||
}
|
||||
|
||||
$Bar = new Bar;
|
||||
$Baz = new Baz;
|
||||
|
||||
$Bar->selfDo($Bar, $Bar);
|
||||
$Baz->selfDo($Baz, $Baz);
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
36
Zend/tests/bug75079_2.phpt
Normal file
36
Zend/tests/bug75079_2.phpt
Normal file
@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Bug #75079 variation without traits
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo
|
||||
{
|
||||
private static $bar = 123;
|
||||
|
||||
static function test(){
|
||||
return function(){
|
||||
return function(){
|
||||
return Foo::$bar;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$f = Foo::test();
|
||||
|
||||
var_dump($f()());
|
||||
|
||||
class A{}
|
||||
$a = new A;
|
||||
var_dump($f->bindTo($a, A::CLASS)()());
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
int(123)
|
||||
|
||||
Fatal error: Uncaught Error: Cannot access private property Foo::$bar in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): A->{closure}()
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
@ -186,7 +186,7 @@ ZEND_METHOD(Closure, call)
|
||||
ZEND_METHOD(Closure, bind)
|
||||
{
|
||||
zval *newthis, *zclosure, *scope_arg = NULL;
|
||||
zend_closure *closure, *new_closure;
|
||||
zend_closure *closure;
|
||||
zend_class_entry *ce, *called_scope;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
|
||||
@ -226,15 +226,6 @@ ZEND_METHOD(Closure, bind)
|
||||
}
|
||||
|
||||
zend_create_closure(return_value, &closure->func, ce, called_scope, newthis);
|
||||
new_closure = (zend_closure *) Z_OBJ_P(return_value);
|
||||
|
||||
/* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
|
||||
if (ZEND_USER_CODE(closure->func.type) && (closure->func.common.scope != new_closure->func.common.scope || (closure->func.op_array.fn_flags & ZEND_ACC_NO_RT_ARENA))) {
|
||||
new_closure->func.op_array.run_time_cache = emalloc(new_closure->func.op_array.cache_size);
|
||||
memset(new_closure->func.op_array.run_time_cache, 0, new_closure->func.op_array.cache_size);
|
||||
|
||||
new_closure->func.op_array.fn_flags |= ZEND_ACC_NO_RT_ARENA;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -669,9 +660,24 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
|
||||
closure->func.op_array.static_variables =
|
||||
zend_array_dup(closure->func.op_array.static_variables);
|
||||
}
|
||||
if (UNEXPECTED(!closure->func.op_array.run_time_cache)) {
|
||||
closure->func.op_array.run_time_cache = func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
|
||||
memset(func->op_array.run_time_cache, 0, func->op_array.cache_size);
|
||||
|
||||
/* Runtime cache is scope-dependent, so we cannot reuse it if the scope changed */
|
||||
if (!closure->func.op_array.run_time_cache
|
||||
|| func->common.scope != scope
|
||||
|| (func->common.fn_flags & ZEND_ACC_NO_RT_ARENA)
|
||||
) {
|
||||
if (!func->op_array.run_time_cache && (func->common.fn_flags & ZEND_ACC_CLOSURE)) {
|
||||
/* If a real closure is used for the first time, we create a shared runtime cache
|
||||
* and remember which scope it is for. */
|
||||
func->common.scope = scope;
|
||||
func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
|
||||
closure->func.op_array.run_time_cache = func->op_array.run_time_cache;
|
||||
} else {
|
||||
/* Otherwise, we use a non-shared runtime cache */
|
||||
closure->func.op_array.run_time_cache = emalloc(func->op_array.cache_size);
|
||||
closure->func.op_array.fn_flags |= ZEND_ACC_NO_RT_ARENA;
|
||||
}
|
||||
memset(closure->func.op_array.run_time_cache, 0, func->op_array.cache_size);
|
||||
}
|
||||
if (closure->func.op_array.refcount) {
|
||||
(*closure->func.op_array.refcount)++;
|
||||
|
Loading…
Reference in New Issue
Block a user