diff --git a/NEWS b/NEWS index 73d7145593f6..495406db192c 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,8 @@ PHP NEWS . Fix too wide type inference for ASSIGN_DIM_OP. (ndossche) . Fix OSS-Fuzz #568005340 (FETCH_DIM_FUNC_ARG partial conversion). (ndossche) . Fix exception checks due to NAN warnings and object empty()'s. (ndossche) + . Fixed bug GH-24270 (JIT loses the called scope of self:: and parent:: calls + in closures). (RV7PR) - PDO: . Fixed a duplicate warning when ATTR_STATEMENT_CLASS is rejected on a diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 471cf55c6543..08704742f8b5 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -9344,7 +9344,7 @@ static int zend_jit_init_static_method_call(zend_jit_ctx *jit, ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce)))); ir_IF_FALSE(if_object); ir_END_PHI_list(values, ir_LOAD_A(jit_EX(This.value.ref))); - ir_PHI_list(values); + scope_ref = ir_PHI_list(values); } else { scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce))); } diff --git a/ext/opcache/tests/jit/gh24270.inc b/ext/opcache/tests/jit/gh24270.inc new file mode 100644 index 000000000000..badcee80a4ba --- /dev/null +++ b/ext/opcache/tests/jit/gh24270.inc @@ -0,0 +1,74 @@ + self::make(); + } + public function boundSelf(): Closure { + return fn() => self::make(); + } + private static function make() { + return new static(); + } +} +class Mid extends Base { + protected static function name() { + return static::class; + } +} +class Child extends Mid { + public function boundParent(): Closure { + return fn() => parent::name(); + } +} +class GrandChild extends Child {} + +class ParentA { + public static function name() { + return static::class; + } +} +class ParentB { + public static function name() { + return static::class; + } +} +trait T { + public static function traitSelf(): Closure { + return fn() => self::make(); + } + public function traitParent(): Closure { + return fn() => parent::name(); + } + public static function make() { + return new static(); + } +} +class A extends ParentA { + use T; +} +class ChildA extends A {} +class B extends ParentB { + use T; +} +class ChildB extends B {} + +$closures = [ + 'self from static method' => Child::staticSelf(), + 'bound self' => (new Child)->boundSelf(), + 'bound parent' => (new GrandChild)->boundParent(), + 'trait self A' => ChildA::traitSelf(), + 'trait self B' => ChildB::traitSelf(), + 'trait parent A' => (new ChildA)->traitParent(), + 'trait parent B' => (new ChildB)->traitParent(), +]; + +$results = []; +for ($i = 0; $i < 100; $i++) { + foreach ($closures as $name => $closure) { + $result = $closure(); + $results[$name][is_object($result) ? $result::class : $result] = true; + } +} +foreach ($results as $name => $classes) { + echo $name, ': ', implode(', ', array_keys($classes)), "\n"; +} diff --git a/ext/opcache/tests/jit/gh24270_001.phpt b/ext/opcache/tests/jit/gh24270_001.phpt new file mode 100644 index 000000000000..dcc1b8700d57 --- /dev/null +++ b/ext/opcache/tests/jit/gh24270_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-24270 001: Function JIT loses the called scope of self:: and parent:: calls in closures +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +opcache.jit_buffer_size=64M +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECT-- +self from static method: Child +bound self: Child +bound parent: GrandChild +trait self A: ChildA +trait self B: ChildB +trait parent A: ChildA +trait parent B: ChildB diff --git a/ext/opcache/tests/jit/gh24270_002.phpt b/ext/opcache/tests/jit/gh24270_002.phpt new file mode 100644 index 000000000000..8425d4122703 --- /dev/null +++ b/ext/opcache/tests/jit/gh24270_002.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-24270 002: Tracing JIT loses the called scope of self:: and parent:: calls in closures +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=tracing +opcache.jit_buffer_size=64M +opcache.jit_hot_func=1 +opcache.jit_hot_loop=1 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECT-- +self from static method: Child +bound self: Child +bound parent: GrandChild +trait self A: ChildA +trait self B: ChildB +trait parent A: ChildA +trait parent B: ChildB