diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c index a05cf6fb792..a0d08b67aa7 100644 --- a/Zend/Optimizer/zend_cfg.c +++ b/Zend/Optimizer/zend_cfg.c @@ -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]; while (b != end) { 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; zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]); break; diff --git a/ext/opcache/tests/opt/gh18107_1.phpt b/ext/opcache/tests/opt/gh18107_1.phpt new file mode 100644 index 00000000000..0bb5b3201f2 --- /dev/null +++ b/ext/opcache/tests/opt/gh18107_1.phpt @@ -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-- + +--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 diff --git a/ext/opcache/tests/opt/gh18107_2.phpt b/ext/opcache/tests/opt/gh18107_2.phpt new file mode 100644 index 00000000000..0f4f66a4591 --- /dev/null +++ b/ext/opcache/tests/opt/gh18107_2.phpt @@ -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-- + +--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