Skip to content

Commit 465cfc4

Browse files
committed
Additional fix for bug #80847.
On x86_64 part of structure may be passed in CPU registers.
1 parent 4dce2f8 commit 465cfc4

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

ext/ffi/ffi.c

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,15 +293,86 @@ static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *s
293293
}
294294
/* }}} */
295295

296+
static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size)
297+
{
298+
zend_ffi_field *field;
299+
300+
ZEND_HASH_FOREACH_PTR(&type->record.fields, field) {
301+
switch (ZEND_FFI_TYPE(field->type)->kind) {
302+
case ZEND_FFI_TYPE_FLOAT:
303+
t->elements[(*i)++] = &ffi_type_float;
304+
break;
305+
case ZEND_FFI_TYPE_DOUBLE:
306+
t->elements[(*i)++] = &ffi_type_double;
307+
break;
308+
#ifdef HAVE_LONG_DOUBLE
309+
case ZEND_FFI_TYPE_LONGDOUBLE:
310+
t->elements[(*i)++] = &ffi_type_longdouble;
311+
break;
312+
#endif
313+
case ZEND_FFI_TYPE_SINT8:
314+
case ZEND_FFI_TYPE_UINT8:
315+
case ZEND_FFI_TYPE_BOOL:
316+
case ZEND_FFI_TYPE_CHAR:
317+
t->elements[(*i)++] = &ffi_type_uint8;
318+
break;
319+
case ZEND_FFI_TYPE_SINT16:
320+
case ZEND_FFI_TYPE_UINT16:
321+
t->elements[(*i)++] = &ffi_type_uint16;
322+
break;
323+
case ZEND_FFI_TYPE_SINT32:
324+
case ZEND_FFI_TYPE_UINT32:
325+
t->elements[(*i)++] = &ffi_type_uint32;
326+
break;
327+
case ZEND_FFI_TYPE_SINT64:
328+
case ZEND_FFI_TYPE_UINT64:
329+
t->elements[(*i)++] = &ffi_type_uint64;
330+
break;
331+
case ZEND_FFI_TYPE_POINTER:
332+
t->elements[(*i)++] = &ffi_type_pointer;
333+
break;
334+
case ZEND_FFI_TYPE_STRUCT: {
335+
zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
336+
/* for unions we use only the first field */
337+
int num_fields = !(field_type->attr & ZEND_FFI_ATTR_UNION) ?
338+
zend_hash_num_elements(&field_type->record.fields) : 1;
339+
340+
if (num_fields > 1) {
341+
size += sizeof(ffi_type*) * (num_fields - 1);
342+
t = erealloc(t, size);
343+
t->elements = (ffi_type**)(t + 1);
344+
}
345+
t = zend_ffi_face_struct_add_fields(t, field_type, i, size);
346+
break;
347+
}
348+
default:
349+
t->elements[(*i)++] = &ffi_type_void;
350+
break;
351+
}
352+
if (type->attr & ZEND_FFI_ATTR_UNION) {
353+
/* for unions we use only the first field */
354+
break;
355+
}
356+
} ZEND_HASH_FOREACH_END();
357+
return t;
358+
}
359+
296360
static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
297361
{
298-
ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*));
362+
/* for unions we use only the first field */
363+
int num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ?
364+
zend_hash_num_elements(&type->record.fields) : 1;
365+
size_t size = sizeof(ffi_type) + sizeof(ffi_type*) * (num_fields + 1);
366+
ffi_type *t = emalloc(size);
367+
int i;
299368

300369
t->size = type->size;
301370
t->alignment = type->align;
302371
t->type = FFI_TYPE_STRUCT;
303372
t->elements = (ffi_type**)(t + 1);
304-
t->elements[0] = NULL;
373+
i = 0;
374+
t = zend_ffi_face_struct_add_fields(t, type, &i, size);
375+
t->elements[i] = NULL;
305376
return t;
306377
}
307378
/* }}} */

ext/ffi/tests/bug80847.phpt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $x->a->b = 42;
3535
$x->a->c = 42.5;
3636
var_dump($x);
3737
$y = $ffi->ffi_bug80847($x);
38-
var_dump($y);
38+
var_dump($x, $y);
3939
?>
4040
--EXPECTF--
4141
object(FFI\CData:struct bug80847_02)#%d (1) {
@@ -47,6 +47,15 @@ object(FFI\CData:struct bug80847_02)#%d (1) {
4747
float(42.5)
4848
}
4949
}
50+
object(FFI\CData:struct bug80847_02)#%d (1) {
51+
["a"]=>
52+
object(FFI\CData:struct bug80847_01)#%d (2) {
53+
["b"]=>
54+
int(42)
55+
["c"]=>
56+
float(42.5)
57+
}
58+
}
5059
object(FFI\CData:struct bug80847_02)#%d (1) {
5160
["a"]=>
5261
object(FFI\CData:struct bug80847_01)#%d (2) {

0 commit comments

Comments
 (0)