Skip to content

Commit 127d6f3

Browse files
committed
Merge branch 'PHP-7.4'
* PHP-7.4: Fix #79096: FFI Struct Segfault
2 parents 77bf144 + 05f3cd2 commit 127d6f3

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

ext/ffi/ffi.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2585,10 +2585,11 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
25852585
ffi_type **arg_types = NULL;
25862586
void **arg_values = NULL;
25872587
uint32_t n, arg_count;
2588-
ffi_arg ret;
2588+
void *ret;
25892589
zend_ffi_type *arg_type;
25902590
ALLOCA_FLAG(arg_types_use_heap = 0)
25912591
ALLOCA_FLAG(arg_values_use_heap = 0)
2592+
ALLOCA_FLAG(ret_use_heap = 0)
25922593

25932594
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
25942595
arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
@@ -2676,7 +2677,8 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
26762677
}
26772678
}
26782679

2679-
ffi_call(&cif, addr, &ret, arg_values);
2680+
ret = do_alloca(MAX(ret_type->size, sizeof(ffi_arg)), ret_use_heap);
2681+
ffi_call(&cif, addr, ret, arg_values);
26802682

26812683
for (n = 0; n < arg_count; n++) {
26822684
if (arg_types[n]->type == FFI_TYPE_STRUCT) {
@@ -2692,7 +2694,8 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
26922694
free_alloca(arg_values, arg_values_use_heap);
26932695
}
26942696

2695-
zend_ffi_cdata_to_zval(NULL, (void*)&ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1);
2697+
zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1);
2698+
free_alloca(ret, ret_use_heap);
26962699

26972700
exit:
26982701
zend_string_release(EX(func)->common.function_name);

ext/ffi/tests/bug79096.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
Bug #79096 (FFI Struct Segfault)
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+
$header = <<<HEADER
11+
struct bug79096 {
12+
uint64_t a;
13+
uint64_t b;
14+
};
15+
16+
struct bug79096 bug79096(void);
17+
HEADER;
18+
19+
if (PHP_OS_FAMILY !== 'Windows') {
20+
$ffi = FFI::cdef($header);
21+
} else {
22+
try {
23+
$ffi = FFI::cdef($header, 'php_zend_test.dll');
24+
} catch (FFI\Exception $ex) {
25+
$dll = $dll = 'php7' . (PHP_ZTS ? 'ts' : '') . (PHP_DEBUG ? '_debug' : '') . '.dll';
26+
$ffi = FFI::cdef($header, $dll);
27+
}
28+
}
29+
30+
$struct = $ffi->bug79096();
31+
var_dump($struct);
32+
?>
33+
--EXPECTF--
34+
object(FFI\CData:struct bug79096)#%d (2) {
35+
["a"]=>
36+
int(1)
37+
["b"]=>
38+
int(1)
39+
}

ext/zend_test/php_test.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,11 @@ extern zend_module_entry zend_test_module_entry;
3030
ZEND_TSRMLS_CACHE_EXTERN()
3131
#endif
3232

33+
struct bug79096 {
34+
uint64_t a;
35+
uint64_t b;
36+
};
37+
38+
ZEND_API struct bug79096 bug79096(void);
39+
3340
#endif

ext/zend_test/test.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,12 @@ ZEND_TSRMLS_CACHE_DEFINE()
360360
#endif
361361
ZEND_GET_MODULE(zend_test)
362362
#endif
363+
364+
struct bug79096 bug79096(void)
365+
{
366+
struct bug79096 b;
367+
368+
b.a = 1;
369+
b.b = 1;
370+
return b;
371+
}

0 commit comments

Comments
 (0)