Skip to content

Commit 1331444

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-16013 and bug #80857: Big endian issues
2 parents 2021a58 + 250e0ff commit 1331444

File tree

3 files changed

+218
-1
lines changed

3 files changed

+218
-1
lines changed

ext/ffi/ffi.c

+46-1
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,27 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
986986
ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
987987
if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
988988
zend_ffi_zval_to_cdata(ret, ret_type, &retval);
989+
990+
#ifdef WORDS_BIGENDIAN
991+
if (ret_type->size < sizeof(ffi_arg)
992+
&& ret_type->kind >= ZEND_FFI_TYPE_UINT8
993+
&& ret_type->kind < ZEND_FFI_TYPE_POINTER) {
994+
/* We need to widen the value (zero extend) */
995+
switch (ret_type->size) {
996+
case 1:
997+
*(ffi_arg*)ret = *(uint8_t*)ret;
998+
break;
999+
case 2:
1000+
*(ffi_arg*)ret = *(uint16_t*)ret;
1001+
break;
1002+
case 4:
1003+
*(ffi_arg*)ret = *(uint32_t*)ret;
1004+
break;
1005+
default:
1006+
break;
1007+
}
1008+
}
1009+
#endif
9891010
}
9901011

9911012
zval_ptr_dtor(&retval);
@@ -2856,7 +2877,31 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
28562877
}
28572878

28582879
if (ZEND_FFI_TYPE(type->func.ret_type)->kind != ZEND_FFI_TYPE_VOID) {
2859-
zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0);
2880+
zend_ffi_type *func_ret_type = ZEND_FFI_TYPE(type->func.ret_type);
2881+
2882+
#ifdef WORDS_BIGENDIAN
2883+
if (func_ret_type->size < sizeof(ffi_arg)
2884+
&& func_ret_type->kind >= ZEND_FFI_TYPE_UINT8
2885+
&& func_ret_type->kind < ZEND_FFI_TYPE_POINTER) {
2886+
2887+
/* We need to narrow the value (truncate) */
2888+
switch (func_ret_type->size) {
2889+
case 1:
2890+
*(uint8_t*)ret = *(ffi_arg*)ret;
2891+
break;
2892+
case 2:
2893+
*(uint16_t*)ret = *(ffi_arg*)ret;
2894+
break;
2895+
case 4:
2896+
*(uint32_t*)ret = *(ffi_arg*)ret;
2897+
break;
2898+
default:
2899+
break;
2900+
}
2901+
}
2902+
#endif
2903+
2904+
zend_ffi_cdata_to_zval(NULL, ret, func_ret_type, BP_VAR_R, return_value, 0, 1, 0);
28602905
} else {
28612906
ZVAL_NULL(return_value);
28622907
}

ext/ffi/tests/gh16013.phpt

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
--TEST--
2+
GH-16013 (endianness issue with FFI)
3+
--EXTENSIONS--
4+
ffi
5+
zend_test
6+
--FILE--
7+
<?php
8+
require_once('utils.inc');
9+
10+
$header = <<<HEADER
11+
enum bug_gh16013_enum {
12+
BUG_GH16013_A = 1,
13+
BUG_GH16013_B = 2,
14+
};
15+
struct bug_gh16013_int_struct {
16+
int field;
17+
};
18+
struct bug_gh16013_callback_struct {
19+
int8_t (*return_int8)(int8_t);
20+
uint8_t (*return_uint8)(uint8_t);
21+
int16_t (*return_int16)(int16_t);
22+
uint16_t (*return_uint16)(uint16_t);
23+
int32_t (*return_int32)(int32_t);
24+
uint32_t (*return_uint32)(uint32_t);
25+
float (*return_float)(float);
26+
struct bug_gh16013_int_struct (*return_struct)(struct bug_gh16013_int_struct);
27+
enum bug_gh16013_enum (*return_enum)(enum bug_gh16013_enum);
28+
};
29+
30+
char bug_gh16013_return_char();
31+
bool bug_gh16013_return_bool();
32+
short bug_gh16013_return_short();
33+
int bug_gh16013_return_int();
34+
enum bug_gh16013_enum bug_gh16013_return_enum();
35+
struct bug_gh16013_int_struct bug_gh16013_return_struct();
36+
HEADER;
37+
38+
if (PHP_OS_FAMILY !== 'Windows') {
39+
$ffi = FFI::cdef($header);
40+
} else {
41+
try {
42+
$ffi = FFI::cdef($header, 'php_zend_test.dll');
43+
} catch (FFI\Exception $ex) {
44+
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
45+
}
46+
}
47+
48+
echo "--- Return values ---\n";
49+
var_dump($ffi->bug_gh16013_return_char());
50+
var_dump($ffi->bug_gh16013_return_bool());
51+
var_dump($ffi->bug_gh16013_return_short());
52+
var_dump($ffi->bug_gh16013_return_int());
53+
var_dump($ffi->bug_gh16013_return_enum());
54+
var_dump($ffi->bug_gh16013_return_struct());
55+
56+
echo "--- Callback values ---\n";
57+
$bug_gh16013_callback_struct = $ffi->new('struct bug_gh16013_callback_struct');
58+
$bug_gh16013_callback_struct->return_int8 = function($val) use($ffi) {
59+
$cdata = $ffi->new('int8_t');
60+
$cdata->cdata = $val;
61+
return $cdata;
62+
};
63+
$bug_gh16013_callback_struct->return_uint8 = function($val) use($ffi) {
64+
$cdata = $ffi->new('uint8_t');
65+
$cdata->cdata = $val;
66+
return $cdata;
67+
};
68+
$bug_gh16013_callback_struct->return_int16 = function($val) use($ffi) {
69+
$cdata = $ffi->new('int16_t');
70+
$cdata->cdata = $val;
71+
return $cdata;
72+
};
73+
$bug_gh16013_callback_struct->return_uint16 = function($val) use($ffi) {
74+
$cdata = $ffi->new('uint16_t');
75+
$cdata->cdata = $val;
76+
return $cdata;
77+
};
78+
$bug_gh16013_callback_struct->return_int32 = function($val) use($ffi) {
79+
$cdata = $ffi->new('int32_t');
80+
$cdata->cdata = $val;
81+
return $cdata;
82+
};
83+
$bug_gh16013_callback_struct->return_uint32 = function($val) use($ffi) {
84+
$cdata = $ffi->new('uint32_t');
85+
$cdata->cdata = $val;
86+
return $cdata;
87+
};
88+
$bug_gh16013_callback_struct->return_float = function($val) use($ffi) {
89+
$cdata = $ffi->new('float');
90+
$cdata->cdata = $val;
91+
return $cdata;
92+
};
93+
$bug_gh16013_callback_struct->return_struct = function($val) use($ffi) {
94+
return $val;
95+
};
96+
$bug_gh16013_callback_struct->return_enum = function($val) use($ffi) {
97+
$cdata = $ffi->new('enum bug_gh16013_enum');
98+
$cdata->cdata = $val;
99+
return $cdata;
100+
};
101+
102+
var_dump(($bug_gh16013_callback_struct->return_int8)(-4));
103+
var_dump(($bug_gh16013_callback_struct->return_uint8)(4));
104+
var_dump(($bug_gh16013_callback_struct->return_int16)(-10000));
105+
var_dump(($bug_gh16013_callback_struct->return_uint16)(10000));
106+
var_dump(($bug_gh16013_callback_struct->return_int32)(-100000));
107+
var_dump(($bug_gh16013_callback_struct->return_uint32)(100000));
108+
var_dump(($bug_gh16013_callback_struct->return_float)(12.34));
109+
$struct = $ffi->new('struct bug_gh16013_int_struct');
110+
$struct->field = 10;
111+
var_dump(($bug_gh16013_callback_struct->return_struct)($struct));
112+
var_dump(($bug_gh16013_callback_struct->return_enum)($ffi->BUG_GH16013_B));
113+
?>
114+
--EXPECT--
115+
--- Return values ---
116+
string(1) "A"
117+
bool(true)
118+
int(12345)
119+
int(123456789)
120+
int(2)
121+
object(FFI\CData:struct bug_gh16013_int_struct)#2 (1) {
122+
["field"]=>
123+
int(123456789)
124+
}
125+
--- Callback values ---
126+
int(-4)
127+
int(4)
128+
int(-10000)
129+
int(10000)
130+
int(-100000)
131+
int(100000)
132+
float(12.34000015258789)
133+
object(FFI\CData:struct bug_gh16013_int_struct)#13 (1) {
134+
["field"]=>
135+
int(10)
136+
}
137+
int(2)

ext/zend_test/test.c

+35
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,41 @@ PHP_ZEND_TEST_API void bug_gh9090_void_int_char_var(int i, char *fmt, ...) {
14961496

14971497
PHP_ZEND_TEST_API int gh11934b_ffi_var_test_cdata;
14981498

1499+
enum bug_gh16013_enum {
1500+
BUG_GH16013_A = 1,
1501+
BUG_GH16013_B = 2,
1502+
};
1503+
1504+
struct bug_gh16013_int_struct {
1505+
int field;
1506+
};
1507+
1508+
PHP_ZEND_TEST_API char bug_gh16013_return_char(void) {
1509+
return 'A';
1510+
}
1511+
1512+
PHP_ZEND_TEST_API bool bug_gh16013_return_bool(void) {
1513+
return true;
1514+
}
1515+
1516+
PHP_ZEND_TEST_API short bug_gh16013_return_short(void) {
1517+
return 12345;
1518+
}
1519+
1520+
PHP_ZEND_TEST_API int bug_gh16013_return_int(void) {
1521+
return 123456789;
1522+
}
1523+
1524+
PHP_ZEND_TEST_API enum bug_gh16013_enum bug_gh16013_return_enum(void) {
1525+
return BUG_GH16013_B;
1526+
}
1527+
1528+
PHP_ZEND_TEST_API struct bug_gh16013_int_struct bug_gh16013_return_struct(void) {
1529+
struct bug_gh16013_int_struct ret;
1530+
ret.field = 123456789;
1531+
return ret;
1532+
}
1533+
14991534
#ifdef HAVE_COPY_FILE_RANGE
15001535
/**
15011536
* This function allows us to simulate early return of copy_file_range by setting the limit_copy_file_range ini setting.

0 commit comments

Comments
 (0)