summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2020-10-28 12:01:28 +0100
committerChristoph M. Becker <cmbecker69@gmx.de>2020-10-28 13:34:56 +0100
commitf547412cba52b499a4a130b0de1b6af2ea746e3a (patch)
treeaaf926688964127bceef640b62a6ff8f0948ded7
parent68dcaa29d8a2d51f0fed5fde9f3543a1338bfe44 (diff)
downloadphp-git-f547412cba52b499a4a130b0de1b6af2ea746e3a.tar.gz
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] <https://github.com/php/php-src/pull/5120> Closes GH-6366.
-rw-r--r--NEWS4
-rw-r--r--ext/ffi/ffi.c4
-rw-r--r--ext/ffi/tests/bug79177.phpt47
3 files changed, 55 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 95de673b3f..017896befa 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,10 @@ PHP NEWS
- DOM:
. Fixed bug #80268 (loadHTML() truncates at NUL bytes). (cmb)
+- FFI:
+ . Fixed bug #79177 (FFI doesn't handle well PHP exceptions within callback).
+ (cmb, Dmitry, Nikita)
+
- IMAP:
. Fixed bug #64076 (imap_sort() does not return FALSE on failure). (cmb)
. Fixed bug #76618 (segfault on imap_reopen). (girgias)
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index f350f91d8a..d119ea050c 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -886,6 +886,10 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
}
free_alloca(fci.params, use_heap);
+ if (EG(exception)) {
+ zend_error(E_ERROR, "Throwing from FFI callbacks is not allowed");
+ }
+
ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
zend_ffi_zval_to_cdata(ret, ret_type, &retval);
diff --git a/ext/ffi/tests/bug79177.phpt b/ext/ffi/tests/bug79177.phpt
new file mode 100644
index 0000000000..d764437b2d
--- /dev/null
+++ b/ext/ffi/tests/bug79177.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Bug #79177 (FFI doesn't handle well PHP exceptions within callback)
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('utils.inc');
+try {
+ ffi_cdef("extern void *zend_printf;", ffi_get_php_dll_name());
+} catch (Throwable $e) {
+ die('skip PHP symbols not available');
+}
+?>
+--FILE--
+<?php
+require_once('utils.inc');
+$php = ffi_cdef("
+typedef char (*zend_write_func_t)(const char *str, size_t str_length);
+extern zend_write_func_t zend_write;
+", ffi_get_php_dll_name());
+
+echo "Before\n";
+
+$originalHandler = clone $php->zend_write;
+$php->zend_write = function($str, $len): string {
+ throw new \RuntimeException('Not allowed');
+};
+try {
+ echo "After\n";
+} catch (\Throwable $exception) {
+ // Do not output anything here, as handler is overridden
+} finally {
+ $php->zend_write = $originalHandler;
+}
+if (isset($exception)) {
+ echo $exception->getMessage(), PHP_EOL;
+}
+?>
+--EXPECTF--
+Before
+
+Warning: Uncaught RuntimeException: Not allowed in %s:%d
+Stack trace:
+#0 %s(%d): {closure}('After\n', 6)
+#1 {main}
+ thrown in %s on line %d
+
+Fatal error: Throwing from FFI callbacks is not allowed in %s on line %d