Skip to content

Commit 8516434

Browse files
committed
Fixed bug #80046
We already protect against optimizing away loop frees in DFA pass, but not in block pass.
1 parent 658ad4d commit 8516434

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ PHP NEWS
1919
- OPcache:
2020
. Fixed bug #80002 (calc free space for new interned string is wrong).
2121
(t-matsuno)
22+
. Fixed bug #80046 (FREE for SWITCH_STRING optimized away). (Nikita)
2223

2324
- PDO:
2425
. Fixed bug #80027 (Terrible performance using $query->fetch on queries with

Zend/tests/bug80046.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Bug #80046: FREE for SWITCH_STRING optimized away
3+
--FILE--
4+
<?php
5+
6+
function test($foo) {
7+
switch ($foo . 'Bar') {
8+
case 'A':
9+
throw new Exception('A');
10+
default:
11+
throw new Exception('Default');
12+
}
13+
}
14+
try {
15+
test('Foo');
16+
} catch (Exception $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
20+
?>
21+
--EXPECT--
22+
Default

ext/opcache/Optimizer/block_pass.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,15 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
921921
if (b->len == 0) {
922922
continue;
923923
}
924-
if (b->flags & ZEND_BB_REACHABLE) {
924+
if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
925+
if (b->flags & ZEND_BB_UNREACHABLE_FREE) {
926+
/* Only keep the FREE for the loop var */
927+
ZEND_ASSERT(op_array->opcodes[b->start].opcode == ZEND_FREE
928+
|| op_array->opcodes[b->start].opcode == ZEND_FE_FREE);
929+
len += b->len = 1;
930+
continue;
931+
}
932+
925933
opline = op_array->opcodes + b->start + b->len - 1;
926934
if (opline->opcode == ZEND_JMP) {
927935
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
959967

960968
/* Copy code of reachable blocks into a single buffer */
961969
for (b = blocks; b < end; b++) {
962-
if (b->flags & ZEND_BB_REACHABLE) {
970+
if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
963971
memcpy(opline, op_array->opcodes + b->start, b->len * sizeof(zend_op));
964972
b->start = opline - new_opcodes;
965973
opline += b->len;
@@ -1083,7 +1091,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
10831091
/* rebuild map (just for printing) */
10841092
memset(cfg->map, -1, sizeof(int) * op_array->last);
10851093
for (n = 0; n < cfg->blocks_count; n++) {
1086-
if (cfg->blocks[n].flags & ZEND_BB_REACHABLE) {
1094+
if (cfg->blocks[n].flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
10871095
cfg->map[cfg->blocks[n].start] = n;
10881096
}
10891097
}

ext/opcache/Optimizer/zend_cfg.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,8 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
575575
}
576576

577577
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
578-
zend_mark_reachable_blocks(op_array, cfg, 0);
579-
580578
cfg->flags |= flags;
579+
zend_mark_reachable_blocks(op_array, cfg, 0);
581580

582581
return SUCCESS;
583582
}

0 commit comments

Comments
 (0)