Skip to content

Commit ede1568

Browse files
committed
Merge branch 'PHP-8.1'
* PHP-8.1: Fix GH-7867: FFI::cast() from pointer to array is broken
2 parents 4543cd3 + 1632ebb commit ede1568

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

ext/ffi/ffi.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -3901,9 +3901,14 @@ ZEND_METHOD(FFI, cast) /* {{{ */
39013901
/* automatically dereference void* pointers ??? */
39023902
cdata->ptr = *(void**)ptr;
39033903
} else if (old_type->kind == ZEND_FFI_TYPE_ARRAY
3904-
&& type->kind == ZEND_FFI_TYPE_POINTER) {
3905-
cdata->ptr = &cdata->ptr_holder;
3906-
cdata->ptr_holder = old_cdata->ptr;
3904+
&& type->kind == ZEND_FFI_TYPE_POINTER
3905+
&& zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) { cdata->ptr = &cdata->ptr_holder;
3906+
cdata->ptr = &cdata->ptr_holder;
3907+
cdata->ptr_holder = old_cdata->ptr;
3908+
} else if (old_type->kind == ZEND_FFI_TYPE_POINTER
3909+
&& type->kind == ZEND_FFI_TYPE_ARRAY
3910+
&& zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->pointer.type), ZEND_FFI_TYPE(type->array.type))) {
3911+
cdata->ptr = old_cdata->ptr_holder;
39073912
} else if (type->size > old_type->size) {
39083913
zend_object_release(&cdata->std);
39093914
zend_throw_error(zend_ffi_exception_ce, "attempt to cast to larger type");

ext/ffi/tests/gh7867.phpt

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
--TEST--
2+
GH-7867 (FFI::cast() from pointer to array is broken)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("ffi")) die("skip ffi extension not available");
6+
?>
7+
--FILE--
8+
<?php
9+
$value = FFI::new('char[26]');
10+
FFI::memcpy($value, implode('', range('a', 'z')), 26);
11+
12+
$slice = FFI::new('char[4]');
13+
14+
echo 'cast from start' . PHP_EOL;
15+
FFI::memcpy($slice, $value, 4);
16+
var_dump($value + 0, $slice, FFI::cast('char[4]', $value));
17+
echo PHP_EOL;
18+
19+
echo 'cast with offset' . PHP_EOL;
20+
FFI::memcpy($slice, $value + 4, 4);
21+
var_dump($value + 4, $slice, FFI::cast('char[4]', $value + 4));
22+
echo PHP_EOL;
23+
?>
24+
--EXPECTF--
25+
cast from start
26+
object(FFI\CData:char*)#%d (1) {
27+
[0]=>
28+
string(1) "a"
29+
}
30+
object(FFI\CData:char[4])#%d (4) {
31+
[0]=>
32+
string(1) "a"
33+
[1]=>
34+
string(1) "b"
35+
[2]=>
36+
string(1) "c"
37+
[3]=>
38+
string(1) "d"
39+
}
40+
object(FFI\CData:char[4])#%d (4) {
41+
[0]=>
42+
string(1) "a"
43+
[1]=>
44+
string(1) "b"
45+
[2]=>
46+
string(1) "c"
47+
[3]=>
48+
string(1) "d"
49+
}
50+
51+
cast with offset
52+
object(FFI\CData:char*)#%d (1) {
53+
[0]=>
54+
string(1) "e"
55+
}
56+
object(FFI\CData:char[4])#%d (4) {
57+
[0]=>
58+
string(1) "e"
59+
[1]=>
60+
string(1) "f"
61+
[2]=>
62+
string(1) "g"
63+
[3]=>
64+
string(1) "h"
65+
}
66+
object(FFI\CData:char[4])#%d (4) {
67+
[0]=>
68+
string(1) "e"
69+
[1]=>
70+
string(1) "f"
71+
[2]=>
72+
string(1) "g"
73+
[3]=>
74+
string(1) "h"
75+
}

0 commit comments

Comments
 (0)