From 465cfc499b9754dafc7b4e3f8ba2d8028baa6da5 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 18 Mar 2021 16:13:42 +0300 Subject: Additional fix for bug #80847. On x86_64 part of structure may be passed in CPU registers. --- ext/ffi/ffi.c | 75 +++++++++++++++++++++++++++++++++++++++++++-- ext/ffi/tests/bug80847.phpt | 11 ++++++- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index ff785065fd..e3da06698f 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -293,15 +293,86 @@ static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *s } /* }}} */ +static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size) +{ + zend_ffi_field *field; + + 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; + case ZEND_FFI_TYPE_STRUCT: { + zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type); + /* for unions we use only the first field */ + int num_fields = !(field_type->attr & ZEND_FFI_ATTR_UNION) ? + zend_hash_num_elements(&field_type->record.fields) : 1; + + if (num_fields > 1) { + size += sizeof(ffi_type*) * (num_fields - 1); + t = erealloc(t, size); + t->elements = (ffi_type**)(t + 1); + } + t = zend_ffi_face_struct_add_fields(t, field_type, i, size); + break; + } + default: + t->elements[(*i)++] = &ffi_type_void; + break; + } + if (type->attr & ZEND_FFI_ATTR_UNION) { + /* for unions we use only the first field */ + break; + } + } ZEND_HASH_FOREACH_END(); + return t; +} + static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */ { - ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*)); + /* for unions we use only the first field */ + int num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ? + zend_hash_num_elements(&type->record.fields) : 1; + size_t size = sizeof(ffi_type) + sizeof(ffi_type*) * (num_fields + 1); + ffi_type *t = emalloc(size); + int i; t->size = type->size; t->alignment = type->align; t->type = FFI_TYPE_STRUCT; t->elements = (ffi_type**)(t + 1); - t->elements[0] = NULL; + i = 0; + t = zend_ffi_face_struct_add_fields(t, type, &i, size); + t->elements[i] = NULL; return t; } /* }}} */ diff --git a/ext/ffi/tests/bug80847.phpt b/ext/ffi/tests/bug80847.phpt index aa90082859..bfa750159c 100644 --- a/ext/ffi/tests/bug80847.phpt +++ b/ext/ffi/tests/bug80847.phpt @@ -35,7 +35,7 @@ $x->a->b = 42; $x->a->c = 42.5; var_dump($x); $y = $ffi->ffi_bug80847($x); -var_dump($y); +var_dump($x, $y); ?> --EXPECTF-- object(FFI\CData:struct bug80847_02)#%d (1) { @@ -47,6 +47,15 @@ object(FFI\CData:struct bug80847_02)#%d (1) { float(42.5) } } +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) { -- cgit v1.2.1