-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix #79177 Check for undefined result in zend_ffi_callback_trampoline. #5120
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 #79177 Check for undefined result in zend_ffi_callback_trampoline. #5120
Conversation
It would be nice to add a test case, but it isn't easy to reproduce this bug with existing callbacks. So, test is not provided right now. Only possible to acheive this case with PHP object handlers right now as those callbacks return complex pointers and not simple values. |
We can't ignore C result value. So, in case of exception in callback, we will have to die (fatal error). |
@dstogov Thank you for reply! I'm not sure that we need to die (fatal error) in this case. I think that better option will be to check if there is a global exception, if it present, then just terminate trampoline call (it will be done automatically after checking EG(exception) later). But I'm agree that we should to check if there is a return value and no exception, in that case we should throw exception and terminate this call. Maybe do you know better way of handling exceptions thrown within FFI callback? With my patch it works perfectly, but I want to double check with you if we can handle this situation better. |
I'm going to commit this patch https://gist.github.com/dstogov/1195bede1f22d169acb6a9d03d22fbfa Exceptions should be caught by the PHP callback itself and it should care about recovery and reporting error to C. |
Please check this test case: use FFI\CData;
$php = FFI::cdef("
typedef unsigned int fake_struct;
typedef fake_struct* (*zend_write_func_t)(const char *str, size_t str_length);
extern zend_write_func_t zend_write;
");
echo "Before", PHP_EOL;
$originalHandler = clone $php->zend_write;
$php->zend_write = function($str, $len): CData {
throw new \RuntimeException('Not allowed');
};
try {
echo "After", PHP_EOL;
} catch (\Throwable $exception) {
// Do not output anything here, as handler is overridden
} finally {
$php->zend_write = $originalHandler;
}
echo get_class($exception), ': ', $exception->getMessage(), PHP_EOL; What it will output for your patch? |
I would also vote not to generate warnings, as it is old-style IMHO ) Better just to pack existing exception as previous exception and throw a new error with previous exception set. |
@dstogov Your patch looks fine to me. I don't see any other way to handle exceptions here. |
This situation can happen when userland exception is thrown within callback body.
a232a7a
to
4318982
Compare
@dstogov With your patch |
It's clear, we can't catch, because we die early. |
I agree, we can remove warning and add note about FFI into uncaught exception error itself |
Is it possible to handle this somehow for |
Let you override zend_fopen(). |
@dstogov @nikic I have one idea about this issue. This issue is only happen for callback that should return pointers to structures and never for scalar types. Thus I want to propose to handle this situation bu returning null values (not undef), so external code should deal with empty pointers (this is typically what we should do) |
@lisachenko In that case it is your job to catch the exception and explicitly return the value you want, and that the library providing the hook expects in an error condition. |
See my previous message, in case of internal PHP exceptions in callbacks that return pointers, result could be filled as And for all other return types we will throw an error immediately (better catchable). |
This is good idea, but I'm looking for a way to use exceptions inside PHP callbacks. Otherwise we should prevent throwing of exceptions within PHP callbacks or wrap this information into specific As of current patch PHP exceptions cant be used inside C callbacks that have return values. |
Different C functions report errors differently (even with scalars). Some returns 0, some negative number, some NULL, some specially formed addresses (e.g. MAP_FAILED) |
Ok, I have checked several language bindings for FFI and handling of exceptions in that languages. And recipe is only one: do not unwind this error back to C code. So, let's proceed with throwing an There are only small chances to implement a wrapper in form of coroutine or special exception class with method UPD1: If C callback doesn't have a return value, then we can use our exception from callback and handle it. |
This has been discussed and agreed upon in a previous PR[1]. [1] <php#5120>
I'm closing this in favor of PR #6366. |
This situation can happen when userland exception is thrown within callback body.