[FFI] Segfault/memory leak on incorrect use of FFI definitions
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- C
- Star
- 40.4k
- Fork
- 8.2k
- Merge trung bình
- 2 ngày 13 giờ
- Pull request đã merge (30 ngày)
- 96
Mô tả
Description
The following code:
<?php
class MyClass
{
public static function do(): void
{
$ffi = FFI::cdef("struct struct1{int x;};struct struct2{int y;};void takesStruct1(struct struct1*);", __DIR__ . "/a.out");
$struct2 = $ffi->new("struct struct2");
$ffi->takesStruct1(FFI::addr($struct2));
}
}
MyClass::do();
With the following C source for a.out (compile with cc -shared test.c):
#include <stdio.h>
struct struct1{int x; int y;};
struct struct2{int x;};
void takesStruct1(struct struct1*){printf("I took a struct1!");}
Resulted in this output:
php: /home/iggyvolz/php-src/ext/ffi/ffi.c:1631: zend_ffi_ctype_name: Assertion `0' failed.
Aborted
With the following gdb backtrace:
#0 __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0)
at ./nptl/pthread_kill.c:44
#1 0x00007ffff6bfcd9f in __pthread_kill_internal (signo=6, threadid=<optimized out>)
at ./nptl/pthread_kill.c:78
#2 0x00007ffff6badf32 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3 0x00007ffff6b98472 in __GI_abort () at ./stdlib/abort.c:79
#4 0x00007ffff6b98395 in __assert_fail_base (
fmt=0x7ffff6d0ca90 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n",
assertion=assertion@entry=0x555555e9582e "0",
file=file@entry=0x555555e95188 "/home/iggyvolz/php-src/ext/ffi/ffi.c", line=line@entry=1631,
function=function@entry=0x555555e97ca0 <__PRETTY_FUNCTION__.58> "zend_ffi_ctype_name")
at ./assert/assert.c:92
#5 0x00007ffff6ba6e32 in __GI___assert_fail (assertion=0x555555e9582e "0",
file=0x555555e95188 "/home/iggyvolz/php-src/ext/ffi/ffi.c", line=1631,
function=0x555555e97ca0 <__PRETTY_FUNCTION__.58> "zend_ffi_ctype_name") at ./assert/assert.c:101
#6 0x0000555555779388 in zend_ffi_ctype_name (buf=0x7fffffffa4e0, type=0x7ffff407f080)
at /home/iggyvolz/php-src/ext/ffi/ffi.c:1631
#7 0x0000555555779932 in zend_ffi_get_class_name (prefix=0x555556dc1ad0, type=0x7ffff407f300)
at /home/iggyvolz/php-src/ext/ffi/ffi.c:1732
#8 0x00005555557799d1 in zend_ffi_cdata_get_class_name (zobj=0x7ffff407f380)
at /home/iggyvolz/php-src/ext/ffi/ffi.c:1745
#9 0x0000555555cfaaee in _build_trace_args (arg=0x7ffff40603c8, str=0x7fffffffa720)
at /home/iggyvolz/php-src/Zend/zend_exceptions.c:517
#10 0x0000555555cfb06d in _build_trace_string (str=0x7fffffffa720, ht=0x7ffff405c6c0, num=0)
at /home/iggyvolz/php-src/Zend/zend_exceptions.c:576
#11 0x0000555555cfb235 in zend_trace_to_string (trace=0x7ffff405c660, include_main=true)
at /home/iggyvolz/php-src/Zend/zend_exceptions.c:602
#12 0x0000555555cfb3e8 in zim_Exception_getTraceAsString (execute_data=0x7ffff4016070,
return_value=0x7fffffffaa90) at /home/iggyvolz/php-src/Zend/zend_exceptions.c:631
#13 0x0000555555c07d8c in zend_call_function (fci=0x7fffffffaa50, fci_cache=0x7fffffffa830)
at /home/iggyvolz/php-src/Zend/zend_execute_API.c:970
#14 0x0000555555cfb6da in zim_Exception___toString (execute_data=0x7ffff4016020,
return_value=0x7fffffffaed0) at /home/iggyvolz/php-src/Zend/zend_exceptions.c:676
#15 0x0000555555c07d8c in zend_call_function (fci=0x7fffffffadc0, fci_cache=0x7fffffffad90)
at /home/iggyvolz/php-src/Zend/zend_execute_API.c:970
#16 0x0000555555c0826a in zend_call_known_function (fn=0x555556d33960, object=0x7ffff4060300,
called_scope=0x555556dc0170, retval_ptr=0x7fffffffaed0, param_count=0, params=0x0, named_params=0x0)
at /home/iggyvolz/php-src/Zend/zend_execute_API.c:1051
#17 0x0000555555cf7b95 in zend_call_known_instance_method (fn=0x555556d33960, object=0x7ffff4060300,
retval_ptr=0x7fffffffaed0, param_count=0, params=0x0) at /home/iggyvolz/php-src/Zend/zend_API.h:853
#18 0x0000555555cf7bcf in zend_call_known_instance_method_with_0_params (fn=0x555556d33960,
object=0x7ffff4060300, retval_ptr=0x7fffffffaed0) at /home/iggyvolz/php-src/Zend/zend_API.h:859
#19 0x0000555555cfc8c0 in zend_exception_error (ex=0x7ffff4060300, severity=1)
at /home/iggyvolz/php-src/Zend/zend_exceptions.c:921
#20 0x0000555555c243e1 in zend_execute_scripts (type=8, retval=0x0, file_count=3)
at /home/iggyvolz/php-src/Zend/zend.c:1888
#21 0x0000555555b61ee2 in php_execute_script (primary_file=0x7fffffffd4f0)
at /home/iggyvolz/php-src/main/main.c:2501
#22 0x0000555555dae79d in do_cli (argc=2, argv=0x555556c29550)
at /home/iggyvolz/php-src/sapi/cli/php_cli.c:966
#23 0x0000555555daf56f in main (argc=2, argv=0x555556c29550)
at /home/iggyvolz/php-src/sapi/cli/php_cli.c:1340
But when I run with this (should-be-equivalent) PHP code:
<?php
$ffi = FFI::cdef("struct struct1{int x;};struct struct2{int y;};void takesStruct1(struct struct1*);", __DIR__ . "/a.out");
$struct2 = $ffi->new("struct struct2");
$ffi->takesStruct1(FFI::addr($struct2));
I receive the correct output:
Fatal error: Uncaught FFI\Exception: Passing incompatible argument 1 of C function 'takesStruct1', expecting 'struct struct1*', found 'struct struct2*' in /home/iggyvolz/phpwayland/testsegfault.php:17
Stack trace:
#0 /.../testsegfault.php(17): FFI->takesStruct1(Object(FFI\CData:struct struct2*))
#1 {main}
thrown in /home/iggyvolz/phpwayland/testsegfault.php on line 17
While debugging this issue, I also found a similar-seeming issue with the following class:
<?php
FFI::cdef("void FAKE_FUNCTION();");
Returns a memory leak in the debug build of PHP:
Fatal error: Uncaught FFI\Exception: Failed resolving C function 'FAKE_FUNCTION' in /home/iggyvolz/phpwayland/testmemleak.php:2
Stack trace:
#0 /home/iggyvolz/phpwayland/testmemleak.php(2): FFI::cdef('void FAKE_FUNCT...')
#1 {main}
thrown in /home/iggyvolz/phpwayland/testmemleak.php on line 2
[Fri Dec 8 07:48:04 2023] Script: '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/Zend/zend_string.h(174) : Freeing 0x00007f7aece02dc0 (40 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec 8 07:48:04 2023] Script: '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/ext/ffi/ffi.c(6628) : Freeing 0x00007f7aece5b118 (24 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec 8 07:48:04 2023] Script: '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/ext/ffi/ffi.c(6559) : Freeing 0x00007f7aece5c540 (56 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec 8 07:48:04 2023] Script: '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/Zend/zend_hash.c(177) : Freeing 0x00007f7aece6c300 (320 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
[Fri Dec 8 07:48:04 2023] Script: '/home/iggyvolz/phpwayland/testmemleak.php'
/home/iggyvolz/php-src/ext/ffi/ffi.c(6440) : Freeing 0x00007f7aece7e000 (88 bytes), script=/home/iggyvolz/phpwayland/testmemleak.php
=== Total 5 memory leaks detected ===
Not sure whether this is a different bug or just the same underlying issue manifesting differently, but they feel similar enough that my suspicion is the latter (I can split this into a separate issue if requested).
PHP Version
PHP 8.3.0
Operating System
Debian 12
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu bằng cách tái hiện lệnh gọi FFI dựa trên class và trường hợp FAKE_FUNCTION chưa được phân giải trong bản build debug của PHP 8.3. Kiểm tra ext/ffi/ffi.c quanh zend_ffi_ctype_name ở dòng 1631 và các vị trí rò rỉ được báo cáo ở các dòng 6440, 6559, 6628. Công việc được xem là hoàn tất khi đối số Struct không tương thích tạo ra ngoại lệ FFI thông thường mà không có assertion, và việc phân giải hàm thất bại không để lại rò rỉ bộ nhớ trong bản build debug.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- c, php
- Lĩnh vực
- backend
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 35/100