Skip to content

Commit 1494e87

Browse files
committed
Merge branch 'PHP-8.0'
* PHP-8.0: Fixed bug #80847 (CData structs with fields of type struct can't be passed as C function argument)
2 parents ebaeb93 + 38ebb55 commit 1494e87

File tree

3 files changed

+79
-59
lines changed

3 files changed

+79
-59
lines changed

ext/ffi/ffi.c

Lines changed: 7 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -295,56 +295,13 @@ static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *s
295295

296296
static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
297297
{
298-
ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*) * (zend_hash_num_elements(&type->record.fields) + 1));
299-
int i;
300-
zend_ffi_field *field;
298+
ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*));
301299

302300
t->size = type->size;
303301
t->alignment = type->align;
304302
t->type = FFI_TYPE_STRUCT;
305303
t->elements = (ffi_type**)(t + 1);
306-
i = 0;
307-
ZEND_HASH_FOREACH_PTR(&type->record.fields, field) {
308-
switch (ZEND_FFI_TYPE(field->type)->kind) {
309-
case ZEND_FFI_TYPE_FLOAT:
310-
t->elements[i] = &ffi_type_float;
311-
break;
312-
case ZEND_FFI_TYPE_DOUBLE:
313-
t->elements[i] = &ffi_type_double;
314-
break;
315-
#ifdef HAVE_LONG_DOUBLE
316-
case ZEND_FFI_TYPE_LONGDOUBLE:
317-
t->elements[i] = &ffi_type_longdouble;
318-
break;
319-
#endif
320-
case ZEND_FFI_TYPE_SINT8:
321-
case ZEND_FFI_TYPE_UINT8:
322-
case ZEND_FFI_TYPE_BOOL:
323-
case ZEND_FFI_TYPE_CHAR:
324-
t->elements[i] = &ffi_type_uint8;
325-
break;
326-
case ZEND_FFI_TYPE_SINT16:
327-
case ZEND_FFI_TYPE_UINT16:
328-
t->elements[i] = &ffi_type_uint16;
329-
break;
330-
case ZEND_FFI_TYPE_SINT32:
331-
case ZEND_FFI_TYPE_UINT32:
332-
t->elements[i] = &ffi_type_uint32;
333-
break;
334-
case ZEND_FFI_TYPE_SINT64:
335-
case ZEND_FFI_TYPE_UINT64:
336-
t->elements[i] = &ffi_type_uint64;
337-
break;
338-
case ZEND_FFI_TYPE_POINTER:
339-
t->elements[i] = &ffi_type_pointer;
340-
break;
341-
default:
342-
efree(t);
343-
return NULL;
344-
}
345-
i++;
346-
} ZEND_HASH_FOREACH_END();
347-
t->elements[i] = NULL;
304+
t->elements[0] = NULL;
348305
return t;
349306
}
350307
/* }}} */
@@ -391,11 +348,7 @@ static ffi_type *zend_ffi_get_type(zend_ffi_type *type) /* {{{ */
391348
kind = type->enumeration.kind;
392349
goto again;
393350
case ZEND_FFI_TYPE_STRUCT:
394-
if (!(type->attr & ZEND_FFI_ATTR_UNION)) {
395-
ffi_type *t = zend_ffi_make_fake_struct_type(type);
396-
return t;
397-
}
398-
break;
351+
return zend_ffi_make_fake_struct_type(type);
399352
default:
400353
break;
401354
}
@@ -2534,18 +2487,13 @@ static int zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type **pass_typ
25342487
kind = type->enumeration.kind;
25352488
goto again;
25362489
case ZEND_FFI_TYPE_STRUCT:
2537-
if (!(type->attr & ZEND_FFI_ATTR_UNION)
2538-
&& Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2490+
if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
25392491
zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
25402492

25412493
if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
2542-
/* Create a fake structure type */
2543-
ffi_type *t = zend_ffi_make_fake_struct_type(type);
2544-
if (t) {
2545-
*pass_type = t;
2546-
arg_values[n] = cdata->ptr;
2547-
break;
2548-
}
2494+
*pass_type = zend_ffi_make_fake_struct_type(type);;
2495+
arg_values[n] = cdata->ptr;
2496+
break;
25492497
}
25502498
}
25512499
zend_ffi_pass_incompatible(arg, type, n, execute_data);

ext/ffi/tests/bug80847.phpt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Bug #80847 (Nested structs)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('ffi')) die('skip ffi extension not available');
6+
if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
7+
?>
8+
--FILE--
9+
<?php
10+
require_once('utils.inc');
11+
$header = <<<HEADER
12+
typedef struct bug80847_01 {
13+
uint64_t b;
14+
double c;
15+
} bug80847_01;
16+
17+
typedef struct bug80847_02 {
18+
bug80847_01 a;
19+
} bug80847_02;
20+
21+
bug80847_02 ffi_bug80847(bug80847_02 s);
22+
HEADER;
23+
24+
if (PHP_OS_FAMILY !== 'Windows') {
25+
$ffi = FFI::cdef($header);
26+
} else {
27+
try {
28+
$ffi = FFI::cdef($header, 'php_zend_test.dll');
29+
} catch (FFI\Exception $ex) {
30+
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
31+
}
32+
}
33+
$x = $ffi->new('bug80847_02');
34+
$x->a->b = 42;
35+
$x->a->c = 42.5;
36+
var_dump($x);
37+
$y = $ffi->ffi_bug80847($x);
38+
var_dump($y);
39+
?>
40+
--EXPECTF--
41+
object(FFI\CData:struct bug80847_02)#%d (1) {
42+
["a"]=>
43+
object(FFI\CData:struct bug80847_01)#%d (2) {
44+
["b"]=>
45+
int(42)
46+
["c"]=>
47+
float(42.5)
48+
}
49+
}
50+
object(FFI\CData:struct bug80847_02)#%d (1) {
51+
["a"]=>
52+
object(FFI\CData:struct bug80847_01)#%d (2) {
53+
["b"]=>
54+
int(52)
55+
["c"]=>
56+
float(32.5)
57+
}
58+
}

ext/zend_test/test.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,17 @@ void bug79177(void)
615615
{
616616
bug79177_cb();
617617
}
618+
619+
typedef struct bug80847_01 {
620+
uint64_t b;
621+
double c;
622+
} bug80847_01;
623+
typedef struct bug80847_02 {
624+
bug80847_01 a;
625+
} bug80847_02;
626+
627+
PHP_ZEND_TEST_API bug80847_02 ffi_bug80847(bug80847_02 s) {
628+
s.a.b += 10;
629+
s.a.c -= 10.0;
630+
return s;
631+
}

0 commit comments

Comments
 (0)