Skip to content

Commit bb265d2

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-18107: Opcache CFG jmp optimization with try-finally breaks the exception table
2 parents b233ed7 + d765b60 commit bb265d2

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

Zend/Optimizer/zend_cfg.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *
143143
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
144144
while (b != end) {
145145
if (b->flags & ZEND_BB_REACHABLE) {
146-
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
146+
/* In case we get here, there is no live try block but there is a live finally block.
147+
* If we do have catch_op set, we need to set it to the first catch block to satisfy
148+
* the constraint try_op <= catch_op <= finally_op */
149+
op_array->try_catch_array[j].try_op =
150+
op_array->try_catch_array[j].catch_op ? op_array->try_catch_array[j].catch_op : b->start;
147151
changed = 1;
148152
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
149153
break;

ext/opcache/tests/opt/gh18107_1.phpt

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

ext/opcache/tests/opt/gh18107_2.phpt

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
GH-18107 (Opcache CFG jmp optimization with try-finally breaks the exception table)
3+
--CREDITS--
4+
SpencerMalone
5+
--EXTENSIONS--
6+
opcache
7+
--INI--
8+
opcache.optimization_level=0x10
9+
opcache.opt_debug_level=0x20000
10+
--FILE--
11+
<?php
12+
13+
if (!isset($badvar)) {
14+
throw new Exception("Should happen");
15+
}
16+
try {
17+
goto foo;
18+
} catch (Throwable $e) {
19+
echo "foo";
20+
foo:;
21+
} finally {
22+
throw new Exception("Should not happen");
23+
}
24+
25+
?>
26+
--EXPECTF--
27+
$_main:
28+
; (lines=%d, args=0, vars=%d, tmps=%d)
29+
; (after optimizer)
30+
; %s
31+
0000 T2 = ISSET_ISEMPTY_CV (isset) CV0($badvar)
32+
0001 JMPNZ T2 0008
33+
0002 V4 = NEW 1 string("Exception")
34+
0003 SEND_VAL_EX string("Should happen") 1
35+
0004 DO_FCALL
36+
0005 THROW V4
37+
0006 CV1($e) = CATCH string("Throwable")
38+
0007 ECHO string("foo")
39+
0008 T6 = FAST_CALL 0010
40+
0009 JMP 0015
41+
0010 V7 = NEW 1 string("Exception")
42+
0011 SEND_VAL_EX string("Should not happen") 1
43+
0012 DO_FCALL
44+
0013 THROW V7
45+
0014 FAST_RET T6
46+
0015 RETURN int(1)
47+
EXCEPTION TABLE:
48+
0006, 0006, 0010, 0014
49+
Fatal error: Uncaught Exception: Should happen in %s:%d
50+
Stack trace:
51+
#0 {main}
52+
thrown in %s on line %d

0 commit comments

Comments
 (0)