Skip to content

Commit 3bb8afd

Browse files
committed
Fix GH-18107: Opcache CFG jmp optimization with try-finally breaks the exception table
If there's a try-finally where the try_op starts on a basic block with a single JMP, and the JMP optimization causes that basic block to become unreachable, then we update try_op. In this case, there is no catch_op, so try_op is erroneously set to 0, we should instead set it to `b->start`.
1 parent c531f3d commit 3bb8afd

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

Zend/Optimizer/zend_cfg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *
144144
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
145145
while (b != end) {
146146
if (b->flags & ZEND_BB_REACHABLE) {
147-
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
147+
op_array->try_catch_array[j].try_op = b->start;
148148
changed = 1;
149149
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
150150
break;

ext/opcache/tests/opt/gh18107.phpt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
GH-18107 (Opcache CFG jmp optimization with try-finally breaks the exception table)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.optimization_level=0x10
7+
opcache.opt_debug_level=0x20000
8+
--FILE--
9+
<?php
10+
11+
if (!isset($badvar)) {
12+
throw new Exception("Should happen");
13+
}
14+
try {
15+
while (true) { }
16+
} finally {
17+
throw new Exception("Should not happen");
18+
}
19+
20+
?>
21+
--EXPECTF--
22+
$_main:
23+
; (lines=%d, args=0, vars=%d, tmps=%d)
24+
; (after optimizer)
25+
; %s
26+
0000 T1 = ISSET_ISEMPTY_CV (isset) CV0($badvar)
27+
0001 JMPNZ T1 0006
28+
0002 V3 = NEW 1 string("Exception")
29+
0003 SEND_VAL_EX string("Should happen") 1
30+
0004 DO_FCALL
31+
0005 THROW V3
32+
0006 JMP 0006
33+
0007 V6 = NEW 1 string("Exception")
34+
0008 SEND_VAL_EX string("Should not happen") 1
35+
0009 DO_FCALL
36+
0010 THROW V6
37+
0011 FAST_RET T5
38+
EXCEPTION TABLE:
39+
0006, -, 0007, 0011
40+
Fatal error: Uncaught Exception: Should happen in %s:%d
41+
Stack trace:
42+
#0 {main}
43+
thrown in %s on line %d

0 commit comments

Comments
 (0)