Skip to content

Commit

Permalink
Fixed bug #80046
Browse files Browse the repository at this point in the history
We already protect against optimizing away loop frees in DFA pass,
but not in block pass.
  • Loading branch information
nikic committed Sep 3, 2020
1 parent 658ad4d commit 8516434
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 5 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions Zend/tests/bug80046.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Bug #80046: FREE for SWITCH_STRING optimized away
--FILE--
<?php

function test($foo) {
switch ($foo . 'Bar') {
case 'A':
throw new Exception('A');
default:
throw new Exception('Default');
}
}
try {
test('Foo');
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
Default
14 changes: 11 additions & 3 deletions ext/opcache/Optimizer/block_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down
3 changes: 1 addition & 2 deletions ext/opcache/Optimizer/zend_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 8516434

Please sign in to comment.