Skip to content

Commit 05aef89

Browse files
committed
Fix #79177: FFI doesn't handle well PHP exceptions within callback
When an FII callback function throws an unhandled exception, it makes not much sense to return value to the C code. Instead, we declare that the return value is undefined in this case, and let userland deal with that.
1 parent 4ef7be2 commit 05aef89

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

ext/ffi/ffi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,10 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
886886
}
887887
free_alloca(fci.params, use_heap);
888888

889+
if (EG(exception)) {
890+
return;
891+
}
892+
889893
ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
890894
if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
891895
zend_ffi_zval_to_cdata(ret, ret_type, &retval);

ext/ffi/tests/bug79177.phpt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
Bug #79177 (FFI doesn't handle well PHP exceptions within callback)
3+
--SKIPIF--
4+
<?php
5+
require_once('skipif.inc');
6+
require_once('utils.inc');
7+
try {
8+
ffi_cdef("extern void *zend_printf;", ffi_get_php_dll_name());
9+
} catch (Throwable $e) {
10+
die('skip PHP symbols not available');
11+
}
12+
?>
13+
--FILE--
14+
<?php
15+
require_once('utils.inc');
16+
$php = ffi_cdef("
17+
typedef char (*zend_write_func_t)(const char *str, size_t str_length);
18+
extern zend_write_func_t zend_write;
19+
", ffi_get_php_dll_name());
20+
21+
echo "Before", PHP_EOL;
22+
23+
$originalHandler = clone $php->zend_write;
24+
$php->zend_write = function($str, $len): string {
25+
throw new \RuntimeException('Not allowed');
26+
};
27+
try {
28+
echo "After", PHP_EOL;
29+
} catch (\Throwable $exception) {
30+
// Do not output anything here, as handler is overridden
31+
} finally {
32+
$php->zend_write = $originalHandler;
33+
}
34+
if (isset($exception)) {
35+
echo $exception->getMessage(), PHP_EOL;
36+
}
37+
?>
38+
--EXPECT--
39+
Before
40+
Not allowed

0 commit comments

Comments
 (0)