-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix GH-18107: Opcache CFG jmp optimization with try-finally breaks the exception table #18110
Conversation
… 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`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure.
You fix problem for for case without catch
blocks. This looks right.
Please also check the case when we have catch
block, but all try
blocks are unreachable. Previously, we set try_op
to the first catch
block, but with your fix we may probably set it not to the first catch
block.
If the try block is unreachable, we first use the catch blocks if one of them is reachable: php-src/Zend/Optimizer/zend_cfg.c Lines 131 to 140 in 8c7e856
This executes before using the finally blocks, i.e. before the code I changed. I also tried some testing with PHP code.
<?php
if (!isset($badvar)) {
throw new Exception("Should happen");
}
try {
goto foo;
} catch (Throwable $e) {
foo:;
} finally {
throw new Exception("Should not happen");
}
Prior to this PR, the try_op and catch_op pointed to the |
Thanks for analyses. The fix should be simple. |
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
.This is a significantly reduced test case from the original code, so the code looks a bit unrealistic but is simple.