]> granicus.if.org Git - php/commitdiff
Fix #79096: FFI Struct Segfault
authorChristoph M. Becker <cmbecker69@gmx.de>
Sun, 12 Jan 2020 13:01:42 +0000 (14:01 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Tue, 14 Jan 2020 15:46:58 +0000 (16:46 +0100)
We must not assume that the size of a function's return value is at
most `sizeof(ffi_arg)`, but rather have to use the size which already
has been determined for the return type if it is larger than
`sizeof(ffi_arg)`.

To be able to have a regression test, we export the required test
function from the zend-test extension, and make sure that the test
can be run on different platforms regardless of whether zend-tests was
built statically or dynamically.

NEWS
ext/ffi/ffi.c
ext/ffi/tests/bug79096.phpt [new file with mode: 0644]
ext/zend_test/php_test.h
ext/zend_test/test.c

diff --git a/NEWS b/NEWS
index ba070d30ae7bdc07607c9312c3d430b6bd6cbdf5..25fd34bd7c3adafca4bf9ce02bf1c4c388917be4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@ PHP                                                                        NEWS
   . Fixed bug #79078 (Hypothetical use-after-free in curl_multi_add_handle()).
     (cmb)
 
+- FFI:
+  . Fixed bug #79096 (FFI Struct Segfault). (cmb)
+
 - MySQLnd:
   . Fixed bug #79084 (mysqlnd may fetch wrong column indexes with MYSQLI_BOTH).
     (cmb)
index 369e6531ace3750565e924f1580d3a73d425edff..f43ba2adc8d27785c0d8fa3d891e235c8b4009c9 100644 (file)
@@ -2613,10 +2613,11 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
        ffi_type **arg_types = NULL;
        void **arg_values = NULL;
        uint32_t n, arg_count;
-       ffi_arg ret;
+       void *ret;
        zend_ffi_type *arg_type;
        ALLOCA_FLAG(arg_types_use_heap = 0)
        ALLOCA_FLAG(arg_values_use_heap = 0)
+       ALLOCA_FLAG(ret_use_heap = 0)
 
        ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
        arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
@@ -2704,7 +2705,8 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
                }
        }
 
-       ffi_call(&cif, addr, &ret, arg_values);
+       ret = do_alloca(MAX(ret_type->size, sizeof(ffi_arg)), ret_use_heap);
+       ffi_call(&cif, addr, ret, arg_values);
 
        for (n = 0; n < arg_count; n++) {
                if (arg_types[n]->type == FFI_TYPE_STRUCT) {
@@ -2720,7 +2722,8 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
                free_alloca(arg_values, arg_values_use_heap);
        }
 
-       zend_ffi_cdata_to_zval(NULL, (void*)&ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1);
+       zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1);
+       free_alloca(ret, ret_use_heap);
 
 exit:
        zend_string_release(EX(func)->common.function_name);
diff --git a/ext/ffi/tests/bug79096.phpt b/ext/ffi/tests/bug79096.phpt
new file mode 100644 (file)
index 0000000..c495efc
--- /dev/null
@@ -0,0 +1,39 @@
+--TEST--
+Bug #79096 (FFI Struct Segfault)
+--SKIPIF--
+<?php
+if (!extension_loaded('ffi')) die('skip ffi extension not available');
+if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
+?>
+--FILE--
+<?php
+$header = <<<HEADER
+struct bug79096 {
+       uint64_t a;
+       uint64_t b;
+};
+
+struct bug79096 bug79096(void);
+HEADER;
+
+if (PHP_OS_FAMILY !== 'Windows') {
+    $ffi = FFI::cdef($header);
+} else {
+    try {
+        $ffi = FFI::cdef($header, 'php_zend_test.dll');
+    } catch (FFI\Exception $ex) {
+        $dll = $dll = 'php7' . (PHP_ZTS ? 'ts' : '') . (PHP_DEBUG ? '_debug' : '') . '.dll';
+        $ffi = FFI::cdef($header, $dll);
+    }
+}
+
+$struct = $ffi->bug79096();
+var_dump($struct);
+?>
+--EXPECTF--
+object(FFI\CData:struct bug79096)#%d (2) {
+  ["a"]=>
+  int(1)
+  ["b"]=>
+  int(1)
+}
index b76155e866b5bce390a429258e7226ab25bf1cca..325484c43480580142af0b941b4d5b18cbfbaf55 100644 (file)
@@ -32,4 +32,11 @@ extern zend_module_entry zend_test_module_entry;
 ZEND_TSRMLS_CACHE_EXTERN()
 #endif
 
+struct bug79096 {
+       uint64_t a;
+       uint64_t b;
+};
+
+ZEND_API struct bug79096 bug79096(void);
+
 #endif
index ad5f2fb44673b978505fabc257ad1edccc566e0e..b097a2412b9f53f20b30fa3de1a9ea5daa69812d 100644 (file)
@@ -319,3 +319,12 @@ ZEND_TSRMLS_CACHE_DEFINE()
 #endif
 ZEND_GET_MODULE(zend_test)
 #endif
+
+struct bug79096 bug79096(void)
+{
+  struct bug79096 b;
+
+  b.a = 1;
+  b.b = 1;
+  return b;
+}