-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix bug #81577: Execute interrupt handler on original opline #7624
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
Conversation
The interrupt handler should be executed while the original opline is set, so that exceptions are thrown from the original opline, rather than the target opline. We should only set the target opline after the interrupt function has run.
This breaks an ability to use an interrupt handler for coroutine scheduling. By design, interrupt handler might transfer control to arbitrary stack frame and opline, but now the target opline is always the same. This won't work with CALL VM, because VM_ENTER won't return. This also probably needs special support for JIT. |
This is why the code checks whether the execute_data/opline has been modified and uses VM_ENTER in that case. We only switch to target opline if they are not changed. Or is the concern here what happens if the coroutine tries to switch back, in which case it will execute the previous opline again, rather than the target? I don't really see how to address this. I think we can just drop the VM_ENTER functionality, it's an unnecessary generalization. |
yes. and this will lead to crash.
I don't think so, and I think, exception in interrupt handlers don't have to be thrown from the original opline. The original bug may be easily fixed by UNDEF_RESULT() without any behaviour breaks |
I can't reproduce the failure, but I suppose, it should be fixed by this patch diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 9979a9b2fb..df756146e4 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -9856,6 +9856,7 @@ ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY)
if (EG(timed_out)) {
zend_timeout();
} else if (zend_interrupt_function) {
+ UNDEF_RESULT();
zend_interrupt_function(execute_data);
ZEND_VM_ENTER();
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 4a26e0c252..83e31f289c 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -3527,6 +3527,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_he
if (EG(timed_out)) {
zend_timeout();
} else if (zend_interrupt_function) {
+ UNDEF_RESULT();
zend_interrupt_function(execute_data);
ZEND_VM_ENTER();
} |
@dstogov Using UNDEF_RESULT() would only work around this specific case. This affects all other unwinding cleanups as well. For example, this one will leak the live var for array_merge() result:
Probably it's possible to construct similar examples where live var is incorrect freed or incorrect unfinished call cleanup happens. |
Codecov Report
@@ Coverage Diff @@
## master #7624 +/- ##
==========================================
- Coverage 67.28% 66.73% -0.55%
==========================================
Files 802 755 -47
Lines 301692 293056 -8636
==========================================
- Hits 202997 195576 -7421
+ Misses 98695 97480 -1215
Continue to review full report at Codecov.
|
Closing as a partial fix for the main issue landed. We couldn't figure out a good way to handle the general issue. |
The interrupt handler should be executed while the original opline
is set, so that exceptions are thrown from the original opline,
rather than the target opline. We should only set the target
opline after the interrupt function has run.
Fixes https://bugs.php.net/bug.php?id=81577.