[php-src] Issue #24252: Opcache: SCCP turns `$c::$m()` into CONST/CONST INIT_STATIC_METHOD_CALL with one cache slot, heap-buffer-overflow
| From: | waroad | Date: | Sun, 11 Oct 2026 02:48:08 +0000 |
| Subject: | [php-src] Issue #24252: Opcache: SCCP turns `$c::$m()` into CONST/CONST INIT_STATIC_METHOD_CALL with one cache slot, heap-buffer-overflow | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-252968@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24252
Author: waroad
> With SCCP enabled and the compact-literals pass off, a dynamic static call whose class and
> method names are both constant-propagated reads past the function's runtime cache in
>
ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER, and a release
> build segfaults.
```php
<?php
class Foo { static function bar() { return "sb"; } }
function f() { $c = "Foo"; $m = "bar"; return $c::$m(); }
echo f(), "\n";
```
```
php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d
opcache.optimization_level=0xA0 static_call.php
```
> opcache.optimization_level=0x7FFEBBFF (the default minus pass
> 11, 0x400) fails the same way. On an ASan build (run with
> USE_ZEND_ALLOC=0):
```
==282==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000003ed8 at pc 0x55a8609a58e4
bp 0x7ffe492d9390 sp 0x7ffe492d9380
READ of size 8 at 0x502000003ed8 thread T0
#0 0x55a8609a58e3 in ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER
Zend/zend_vm_execute.h:7558
#1 0x55a860c28b6f in execute_ex Zend/zend_vm_execute.h:111556
#2 0x55a860c71830 in zend_execute Zend/zend_vm_execute.h:116021
0x502000003ed8 is located 0 bytes to the right of 8-byte region [0x502000003ed0,0x502000003ed8)
allocated by thread T0 here:
#4 0x55a86091962d in init_func_run_time_cache_i Zend/zend_execute.c:4511
#6 0x55a86097b67f in ZEND_INIT_FCALL_SPEC_CONST_HANDLER Zend/zend_vm_execute.h:4194
```
> Expected sb, which is what the script prints with opcache off
> and at the default optimization level.
> Found at commit b527e1b34ee97f4ea402e36a641509af7436759d and still reproduces at
> 12df76792026cd62dbbfdf78a426919afe3e0011. A release build segfaults (exit 139, no output) at both
> optimization levels above.
> Looks like SCCP replaces the two operands one at a time:
> zend_optimizer_update_op1_const()
> (Zend/Optimizer/zend_optimizer.c:318-326) sees op2 still a CV and allocates one slot, then
> zend_optimizer_update_op2_const() (zend_optimizer.c:508-514) sees
> op1 already CONST and allocates nothing, while the CONST/CONST handler uses two slots (class and
> function). The default level hides it because pass 11 reallocates all cache slots.
I can send a patch if that helps.
Found with an LLM-based testing tool. As CONTRIBUTING.md asks, the paragraphs in > quotes were
written with Claude; I ran every command myself.