]> granicus.if.org Git - php/commitdiff
Fix #79177: FFI doesn't handle well PHP exceptions within callback
authorChristoph M. Becker <cmbecker69@gmx.de>
Wed, 28 Oct 2020 11:01:28 +0000 (12:01 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Wed, 28 Oct 2020 12:34:56 +0000 (13:34 +0100)
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.

NEWS
ext/ffi/ffi.c
ext/ffi/tests/bug79177.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 95de673b3f9f3ee9e6f1ef45c68d4d41dffe5d51..017896befac85033f54af34a43fd5b7038626be7 100644 (file)
--- 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)
index f350f91d8a3c29cd79ab7f225270fa0888dff9be..d119ea050cbf52184f78ae7585a500b4dd31173c 100644 (file)
@@ -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 (file)
index 0000000..d764437
--- /dev/null
@@ -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