我有一个 Rust 函数,它将一个字节数组传递给 C#:
#[no_mangle]
pub extern "C" fn get_bytes(len: &mut i32, bytes: *mut *mut u8) {
let mut buf : Vec<u8> = get_data();
buf.shrink_to_fit();
// Set the output values
*len = buf.len() as i32;
unsafe {
*bytes = buf.as_mut_ptr();
}
std::mem::forget(buf);
}
我可以从C#中调用它而不崩溃。(取而代之的是崩溃,我假设这是正确的,但不能百分之百确定)。
[DllImport("my_lib")] static extern void get_bytes(ref int len,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref byte[] bytes);
void test()
{
int len = 0;
byte[] bytes = null;
get_bytes(ref len, ref bytes);
}
接着我使用了bytes
,但我知道这块内存需要由Rust进行释放。因此我有另一个Rust函数来释放它:
#[no_mangle]
pub extern "C" fn free_bytes(len: i32, bytes: *mut *mut u8) {
// also tried with: -------------- bytes: *mut u8
assert!(len > 0);
// Rebuild the vec
let v = unsafe { Vec::from_raw_parts(bytes, len as usize, len as usize) };
//println!("bytes to free: {:?}", v);
drop(v); // or it could be implicitly dropped
}
对应的C#代码。调用会导致我的应用崩溃:
[DllImport("my_lib")] extern void free_bytes(int len, ref byte[] bytes);
void test()
{
int len = 0;
byte[] bytes = null;
get_bytes(ref len, ref bytes);
// copy bytes to managed memory
bytes[] copy = new byte[len];
bytes.CopyTo(copy, 0);
// free the unmanaged memory
free_bytes(len, ref bytes); // crash occurs when executing this function
}
我看到Vec::from_parts_raw
“非常不安全”。由于“capacity
需要是指针分配的容量”,我还尝试在Rust和C#之间传递容量而没有使用shrink_to_fit
来保留长度和容量,但也导致崩溃。
我假设from_parts_raw
会恢复堆上的现有内存,但我注意到在C#中的字节内容(在Visual Studio中显示)与Rust中的内容并不匹配(通过“bytes to free”打印)。那么我的错误在于如何回收要释放的 Vec<u8>
,在Rust接受的类型上(例如*mut u8
与*mut *mut u8
),在我的 C#DllImport
中,还是其他地方?
Vec::from_raw_parts(*bytes, len as usize, len as usize)
,对吧? - Jmbbyte[]
,但这并不理想。 - user655321