]> granicus.if.org Git - php/commitdiff
Additional fix for bug #80847.
authorDmitry Stogov <dmitry@zend.com>
Thu, 18 Mar 2021 13:13:42 +0000 (16:13 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 18 Mar 2021 13:13:42 +0000 (16:13 +0300)
On x86_64 part of structure may be passed in CPU registers.

ext/ffi/ffi.c
ext/ffi/tests/bug80847.phpt

index ff785065fd44840a7b7b6c58c8063174915fadbf..e3da06698f6598f2627e8c9f16398785a50b3657 100644 (file)
@@ -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;
 }
 /* }}} */
index aa90082859013f8dc90eef7f139a9da8beb5a345..bfa750159c8d2f6eacb37c8c894917202d6a2e30 100644 (file)
@@ -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) {