[php-src] Issue #24234: Opcache: optimizer overwrites the operator of ASSIGN_STATIC_PROP_OP, so `$c::$$n += 3` segfaults or computes `|=`

From: Date: Sat, 10 Oct 2026 07:07:50 +0000
Subject: [php-src] Issue #24234: Opcache: optimizer overwrites the operator of ASSIGN_STATIC_PROP_OP, so `$c::$$n += 3` segfaults or computes `|=`
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-252962@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24234 Author: waroad > With opcache enabled, a compound assignment to a static property with a variable class name > ($c::$$n += 2) runs with a corrupted operator: UBSan reports an > out-of-bounds index in zend_binary_op(), and a release build > segfaults or quietly applies a different operator. ```php <?php class K { public static $s = 5; } function f() { $c = "K"; $n = "s"; $c::$$n += 2; return K::$s; } var_dump(f()); ``` ``` php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 reduced.php ``` ``` Zend/zend_execute.c:1668:24: runtime error: index 24 out of bounds for type '<unknown> *[12]' #0 in zend_binary_op Zend/zend_execute.c:1668 #1 in ZEND_ASSIGN_STATIC_PROP_OP_SPEC_HANDLER Zend/zend_vm_execute.h:822 #2 in execute_ex Zend/zend_vm_execute.h:110590 #3 in zend_execute Zend/zend_vm_execute.h:116021 #4 in zend_execute_script Zend/zend.c:1980 ``` > I expected int(7) (5 + 2), the same as with opcache off. > opcache.file_update_protection=0 is only there because the file is > new; with an older file, -d opcache.enable_cli=1 alone is enough. > Found at commit b527e1b34ee97f4ea402e36a641509af7436759d, and the UBSan report still appears at > c79284711bd8. A release build segfaults on this script (exit 139, no output). With one more cache > slot in the function, the corrupted operator happens to be a valid one > (ZEND_BW_OR). Then both builds print > int(7) with no diagnostic, while opcache off and > opcache.optimization_level=0 print > int(8): ```php <?php class K { public static $s = 5; } function g() {} function f() { g(); $c = "K"; $n = "s"; $c::$$n += 3; } f(); var_dump(K::$s); ``` > The opcode dump (opcache.opt_debug_level=0x30000) shows > ASSIGN_STATIC_PROP_OP (ADD) before the optimizer and > ASSIGN_STATIC_PROP_OP (ASSIGN_STATIC_PROP) after it. My guess is > that zend_optimizer_update_op2_const() and > zend_optimizer_update_op1_const() in Zend/Optimizer/zend_optimizer.c > treat ASSIGN_STATIC_PROP_OP like the other static-prop opcodes and write the cache slot into > opline->extended_value. For this opcode that field holds the > operator, and the slot belongs in (opline+1)->extended_value. The > op1 path can be hit with K::${N} += 1 (where ê¥à#BþÕ > ‰™&óR(‡N is a user constant) at > opcache.optimization_level=0x4001. Found with an LLM-based testing tool. As CONTRIBUTING.md asks, the paragraphs in > quotes were written with Claude; I ran every command myself.

« previous php.bugs (#252962) next »