summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2021-03-17 09:55:20 +0300
committerDmitry Stogov <dmitry@zend.com>2021-03-17 09:55:20 +0300
commit38ebb55c7c16486c2603f4df906444ee9d651ad4 (patch)
tree58fa5154324fdf53f4eaf5d2a309a9213977e664
parent82622d7583300afb077e819c4a84ef5218bb6e0e (diff)
downloadphp-git-38ebb55c7c16486c2603f4df906444ee9d651ad4.tar.gz
Fixed bug #80847 (CData structs with fields of type struct can't be passed as C function argument)
-rw-r--r--NEWS4
-rw-r--r--ext/ffi/ffi.c66
-rw-r--r--ext/ffi/tests/bug80847.phpt58
-rw-r--r--ext/zend_test/test.c14
4 files changed, 83 insertions, 59 deletions
diff --git a/NEWS b/NEWS
index 452c9889d9..cf7cc8ed1c 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,10 @@ PHP NEWS
- Dba:
. Fixed bug #80817 (dba_popen() may cause segfault during RSHUTDOWN). (cmb)
+- FFI:
+ . Fixed bug #80847 (CData structs with fields of type struct can't be passed
+ as C function argument). (Nickolas Daniel da Silva, Dmitry)
+
- IMAP:
. Fixed bug #80800 (imap_open() fails when the flags parameter includes
CL_EXPUNGE). (girgias)
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index 2ca1cad90d..ff785065fd 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -295,56 +295,13 @@ static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *s
static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
{
- ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*) * (zend_hash_num_elements(&type->record.fields) + 1));
- int i;
- zend_ffi_field *field;
+ ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*));
t->size = type->size;
t->alignment = type->align;
t->type = FFI_TYPE_STRUCT;
t->elements = (ffi_type**)(t + 1);
- i = 0;
- ZEND_HASH_FOREACH_PTR(&type->record.fields, field) {
- switch (ZEND_FFI_TYPE(field->type)->kind) {
- case ZEND_FFI_TYPE_FLOAT:
- t->elements[i] = &ffi_type_float;
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- t->elements[i] = &ffi_type_double;
- break;
-#ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- t->elements[i] = &ffi_type_longdouble;
- break;
-#endif
- case ZEND_FFI_TYPE_SINT8:
- case ZEND_FFI_TYPE_UINT8:
- case ZEND_FFI_TYPE_BOOL:
- case ZEND_FFI_TYPE_CHAR:
- t->elements[i] = &ffi_type_uint8;
- break;
- case ZEND_FFI_TYPE_SINT16:
- case ZEND_FFI_TYPE_UINT16:
- t->elements[i] = &ffi_type_uint16;
- break;
- case ZEND_FFI_TYPE_SINT32:
- case ZEND_FFI_TYPE_UINT32:
- t->elements[i] = &ffi_type_uint32;
- break;
- case ZEND_FFI_TYPE_SINT64:
- case ZEND_FFI_TYPE_UINT64:
- t->elements[i] = &ffi_type_uint64;
- break;
- case ZEND_FFI_TYPE_POINTER:
- t->elements[i] = &ffi_type_pointer;
- break;
- default:
- efree(t);
- return NULL;
- }
- i++;
- } ZEND_HASH_FOREACH_END();
- t->elements[i] = NULL;
+ t->elements[0] = NULL;
return t;
}
/* }}} */
@@ -391,11 +348,7 @@ again:
kind = type->enumeration.kind;
goto again;
case ZEND_FFI_TYPE_STRUCT:
- if (!(type->attr & ZEND_FFI_ATTR_UNION)) {
- ffi_type *t = zend_ffi_make_fake_struct_type(type);
- return t;
- }
- break;
+ return zend_ffi_make_fake_struct_type(type);
default:
break;
}
@@ -2534,18 +2487,13 @@ again:
kind = type->enumeration.kind;
goto again;
case ZEND_FFI_TYPE_STRUCT:
- if (!(type->attr & ZEND_FFI_ATTR_UNION)
- && Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
+ if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
- /* Create a fake structure type */
- ffi_type *t = zend_ffi_make_fake_struct_type(type);
- if (t) {
- *pass_type = t;
- arg_values[n] = cdata->ptr;
- break;
- }
+ *pass_type = zend_ffi_make_fake_struct_type(type);;
+ arg_values[n] = cdata->ptr;
+ break;
}
}
zend_ffi_pass_incompatible(arg, type, n, execute_data);
diff --git a/ext/ffi/tests/bug80847.phpt b/ext/ffi/tests/bug80847.phpt
new file mode 100644
index 0000000000..aa90082859
--- /dev/null
+++ b/ext/ffi/tests/bug80847.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Bug #80847 (Nested structs)
+--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
+require_once('utils.inc');
+$header = <<<HEADER
+ typedef struct bug80847_01 {
+ uint64_t b;
+ double c;
+ } bug80847_01;
+
+ typedef struct bug80847_02 {
+ bug80847_01 a;
+ } bug80847_02;
+
+ bug80847_02 ffi_bug80847(bug80847_02 s);
+HEADER;
+
+if (PHP_OS_FAMILY !== 'Windows') {
+ $ffi = FFI::cdef($header);
+} else {
+ try {
+ $ffi = FFI::cdef($header, 'php_zend_test.dll');
+ } catch (FFI\Exception $ex) {
+ $ffi = FFI::cdef($header, ffi_get_php_dll_name());
+ }
+}
+$x = $ffi->new('bug80847_02');
+$x->a->b = 42;
+$x->a->c = 42.5;
+var_dump($x);
+$y = $ffi->ffi_bug80847($x);
+var_dump($y);
+?>
+--EXPECTF--
+object(FFI\CData:struct bug80847_02)#%d (1) {
+ ["a"]=>
+ object(FFI\CData:struct bug80847_01)#%d (2) {
+ ["b"]=>
+ int(42)
+ ["c"]=>
+ float(42.5)
+ }
+}
+object(FFI\CData:struct bug80847_02)#%d (1) {
+ ["a"]=>
+ object(FFI\CData:struct bug80847_01)#%d (2) {
+ ["b"]=>
+ int(52)
+ ["c"]=>
+ float(32.5)
+ }
+}
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index bd33e7c331..4e7f55d1b1 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -665,3 +665,17 @@ void bug79177(void)
{
bug79177_cb();
}
+
+typedef struct bug80847_01 {
+ uint64_t b;
+ double c;
+} bug80847_01;
+typedef struct bug80847_02 {
+ bug80847_01 a;
+} bug80847_02;
+
+PHP_ZEND_TEST_API bug80847_02 ffi_bug80847(bug80847_02 s) {
+ s.a.b += 10;
+ s.a.c -= 10.0;
+ return s;
+}