From c317bdc0713efb234ca7deaa6f057f053aa3c950 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 6 Jan 2026 00:01:51 +0100 Subject: [PATCH] Fix block_pass JMP[N]Z optimization In the following optimization: JMPZ(X,L1) JMP(L2) L1: -> JMPNZ(X,L2) NOP L1 must not be followed by another block, so that it may safely be followed by the block containing the JMPNZ. get_next_block() is used to verify L1 is the direct follower. This function also skips empty blocks, including live, empty target blocks, which will then implicitly follow the new follow block. This will result in L1 being followed by two separate blocks, which is not possible. Resolve this by get_next_block() stopping at target blocks. Fixes OSS-Fuzz #472563272 --- Zend/Optimizer/block_pass.c | 2 +- ext/opcache/tests/oss-fuzz-472563272.phpt | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/oss-fuzz-472563272.phpt diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index 6fcbd04f12af5..ee70d021f4a92 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -1152,7 +1152,7 @@ static zend_always_inline zend_basic_block *get_next_block(const zend_cfg *cfg, } next_block++; } - while (next_block->len == 0 && !(next_block->flags & ZEND_BB_PROTECTED)) { + while (next_block->len == 0 && !(next_block->flags & (ZEND_BB_TARGET|ZEND_BB_PROTECTED))) { next_block = cfg->blocks + next_block->successors[0]; } return next_block; diff --git a/ext/opcache/tests/oss-fuzz-472563272.phpt b/ext/opcache/tests/oss-fuzz-472563272.phpt new file mode 100644 index 0000000000000..5bd057123fa24 --- /dev/null +++ b/ext/opcache/tests/oss-fuzz-472563272.phpt @@ -0,0 +1,14 @@ +--TEST-- +OSS-Fuzz #472563272 +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + +===DONE=== +--EXPECT-- +===DONE===