[php-src] PR #24143: Fix GH-23911: Cached static closure keeps static:: of the first called class
| From: | Roman3349 | Date: | Mon, 05 Oct 2026 19:30:20 +0000 |
| Subject: | [php-src] PR #24143: Fix GH-23911: Cached static closure keeps static:: of the first called class | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39181@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24143
Author: Roman3349
Fixes GH-23911
The stateless closure cache introduced in GH-23203 stores a single closure per
ZEND_DECLARE_LAMBDA_FUNCTION opline. All subclasses share the declaring
op_array, so the closure created for the first called scope was returned for
every other called scope. This broke static::, new static() and
get_called_class() inside static closures in inherited methods:
class A {
public static function name(): string {
return (static fn () => static::class)();
}
}
class B extends A {}
class C extends A {}
var_dump(B::name(), C::name()); // "B", "B" instead of "B",
"C"
The fix stores the called scope together with the cached closure (a two-slot
cache, like other polymorphic runtime caches) and only reuses the closure when
the called scope matches. The slot is only filled once. Replacing the cached
closure on a mismatch would push a new entry onto EG(lambda_cache) each time,
which is only freed at request shutdown, so alternating called scopes would
grow it without bounds. Other called scopes take the uncached path, which is
how every call behaved before 8.6.
The JIT does not compile this opcode (it calls the VM handler), so no JIT changes
are needed.