From 04e77d2dea03955b987bc6e253ea236c2c7a12aa Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 3 Sep 2020 11:16:50 +0200 Subject: [PATCH] Fixed bug #80046 We already protect against optimizing away loop frees in DFA pass, but not in block pass. --- NEWS | 1 + Zend/tests/bug80046.phpt | 22 ++++++++++++++++++++++ ext/opcache/Optimizer/block_pass.c | 14 +++++++++++--- ext/opcache/Optimizer/zend_cfg.c | 3 +-- 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 Zend/tests/bug80046.phpt diff --git a/NEWS b/NEWS index e2cb05e949..9eaa1b1c58 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ PHP NEWS - OPcache: . Fixed bug #80002 (calc free space for new interned string is wrong). (t-matsuno) + . Fixed bug #80046 (FREE for SWITCH_STRING optimized away). (Nikita) - PDO: . Fixed bug #80027 (Terrible performance using $query->fetch on queries with diff --git a/Zend/tests/bug80046.phpt b/Zend/tests/bug80046.phpt new file mode 100644 index 0000000000..87a493c203 --- /dev/null +++ b/Zend/tests/bug80046.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #80046: FREE for SWITCH_STRING optimized away +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Default diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 3327ec86df..17b89c4d53 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -921,7 +921,15 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op if (b->len == 0) { continue; } - if (b->flags & ZEND_BB_REACHABLE) { + if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) { + if (b->flags & ZEND_BB_UNREACHABLE_FREE) { + /* Only keep the FREE for the loop var */ + ZEND_ASSERT(op_array->opcodes[b->start].opcode == ZEND_FREE + || op_array->opcodes[b->start].opcode == ZEND_FE_FREE); + len += b->len = 1; + continue; + } + opline = op_array->opcodes + b->start + b->len - 1; if (opline->opcode == ZEND_JMP) { zend_basic_block *next = b + 1; @@ -959,7 +967,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op /* Copy code of reachable blocks into a single buffer */ for (b = blocks; b < end; b++) { - if (b->flags & ZEND_BB_REACHABLE) { + if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) { memcpy(opline, op_array->opcodes + b->start, b->len * sizeof(zend_op)); b->start = opline - new_opcodes; opline += b->len; @@ -1083,7 +1091,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op /* rebuild map (just for printing) */ memset(cfg->map, -1, sizeof(int) * op_array->last); for (n = 0; n < cfg->blocks_count; n++) { - if (cfg->blocks[n].flags & ZEND_BB_REACHABLE) { + if (cfg->blocks[n].flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) { cfg->map[cfg->blocks[n].start] = n; } } diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 66c15be311..76c829bb3e 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -575,9 +575,8 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } /* Build CFG, Step 4, Mark Reachable Basic Blocks */ - zend_mark_reachable_blocks(op_array, cfg, 0); - cfg->flags |= flags; + zend_mark_reachable_blocks(op_array, cfg, 0); return SUCCESS; } -- 2.50.1