Merge branch 'PHP-8.4'

* PHP-8.4:
  Fix GH-18107: Opcache CFG jmp optimization with try-finally breaks the exception table
This commit is contained in:
Niels Dossche 2025-03-21 13:58:54 +01:00
commit bb265d2700
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
3 changed files with 102 additions and 1 deletions

View file

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

View file

@ -0,0 +1,45 @@
--TEST--
GH-18107 (Opcache CFG jmp optimization with try-finally breaks the exception table)
--CREDITS--
SpencerMalone
--EXTENSIONS--
opcache
--INI--
opcache.optimization_level=0x10
opcache.opt_debug_level=0x20000
--FILE--
<?php
if (!isset($badvar)) {
throw new Exception("Should happen");
}
try {
while (true) { }
} finally {
throw new Exception("Should not happen");
}
?>
--EXPECTF--
$_main:
; (lines=%d, args=0, vars=%d, tmps=%d)
; (after optimizer)
; %s
0000 T1 = ISSET_ISEMPTY_CV (isset) CV0($badvar)
0001 JMPNZ T1 0006
0002 V3 = NEW 1 string("Exception")
0003 SEND_VAL_EX string("Should happen") 1
0004 DO_FCALL
0005 THROW V3
0006 JMP 0006
0007 V6 = NEW 1 string("Exception")
0008 SEND_VAL_EX string("Should not happen") 1
0009 DO_FCALL
0010 THROW V6
0011 FAST_RET T5
EXCEPTION TABLE:
0006, -, 0007, 0011
Fatal error: Uncaught Exception: Should happen in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View file

@ -0,0 +1,52 @@
--TEST--
GH-18107 (Opcache CFG jmp optimization with try-finally breaks the exception table)
--CREDITS--
SpencerMalone
--EXTENSIONS--
opcache
--INI--
opcache.optimization_level=0x10
opcache.opt_debug_level=0x20000
--FILE--
<?php
if (!isset($badvar)) {
throw new Exception("Should happen");
}
try {
goto foo;
} catch (Throwable $e) {
echo "foo";
foo:;
} finally {
throw new Exception("Should not happen");
}
?>
--EXPECTF--
$_main:
; (lines=%d, args=0, vars=%d, tmps=%d)
; (after optimizer)
; %s
0000 T2 = ISSET_ISEMPTY_CV (isset) CV0($badvar)
0001 JMPNZ T2 0008
0002 V4 = NEW 1 string("Exception")
0003 SEND_VAL_EX string("Should happen") 1
0004 DO_FCALL
0005 THROW V4
0006 CV1($e) = CATCH string("Throwable")
0007 ECHO string("foo")
0008 T6 = FAST_CALL 0010
0009 JMP 0015
0010 V7 = NEW 1 string("Exception")
0011 SEND_VAL_EX string("Should not happen") 1
0012 DO_FCALL
0013 THROW V7
0014 FAST_RET T6
0015 RETURN int(1)
EXCEPTION TABLE:
0006, 0006, 0010, 0014
Fatal error: Uncaught Exception: Should happen in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d