Skip to content

Commit f547412

Browse files
committed
Fix #79177: FFI doesn't handle well PHP exceptions within callback
We have to error on unhandled exceptions in FFI callbacks, to avoid passing back undefined values. This has been discussed and agreed upon in a previous PR[1]. [1] <#5120> Closes GH-6366.
1 parent 68dcaa2 commit f547412

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ PHP NEWS
1414
- DOM:
1515
. Fixed bug #80268 (loadHTML() truncates at NUL bytes). (cmb)
1616

17+
- FFI:
18+
. Fixed bug #79177 (FFI doesn't handle well PHP exceptions within callback).
19+
(cmb, Dmitry, Nikita)
20+
1721
- IMAP:
1822
. Fixed bug #64076 (imap_sort() does not return FALSE on failure). (cmb)
1923
. Fixed bug #76618 (segfault on imap_reopen). (girgias)

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+
zend_error(E_ERROR, "Throwing from FFI callbacks is not allowed");
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: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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\n";
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\n";
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+
--EXPECTF--
39+
Before
40+
41+
Warning: Uncaught RuntimeException: Not allowed in %s:%d
42+
Stack trace:
43+
#0 %s(%d): {closure}('After\n', 6)
44+
#1 {main}
45+
thrown in %s on line %d
46+
47+
Fatal error: Throwing from FFI callbacks is not allowed in %s on line %d

0 commit comments

Comments
 (0)