[英]How to free the memory of a string returned from Rust in C#?
I have these two functions exposed from Rust 我从Rust中暴露了这两个函数
extern crate libc;
use std::mem;
use std::ffi::{CString, CStr};
use libc::c_char;
pub static FFI_LIB_VERSION: &'static str = env!("CARGO_PKG_VERSION"); // '
#[no_mangle]
pub extern "C" fn rustffi_get_version() -> *const c_char {
let s = CString::new(FFI_LIB_VERSION).unwrap();
let p = s.as_ptr();
mem::forget(s);
p as *const _
}
#[no_mangle]
pub extern "C" fn rustffi_get_version_free(s: *mut c_char) {
unsafe {
if s.is_null() {
return;
}
let c_str: &CStr = CStr::from_ptr(s);
let bytes_len: usize = c_str.to_bytes_with_nul().len();
let temp_vec: Vec<c_char> = Vec::from_raw_parts(s, bytes_len, bytes_len);
}
}
fn main() {}
They are imported by C# as below 它们由C#导入,如下所示
namespace rustFfiLibrary
{
public class RustFfiApi
{
[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version")]
public static extern string rustffi_get_version();
[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version_free")]
public static extern void rustffi_get_version_free(string s);
}
}
The memory of the string returned from rustffi_get_version
is not managed by Rust anymore as mem::forget
has been called. 从
rustffi_get_version
返回的字符串的内存不再由Rust管理,因为已经调用了mem::forget
。 In C#, I want to call the get version function, get the string, and then pass it back to Rust for memory deallocation like below. 在C#中,我想调用get version函数,获取字符串,然后将其传递给Rust进行内存释放,如下所示。
public class RustService
{
public static string GetVersion()
{
string temp = RustFfiApi.rustffi_get_version();
string ver = (string)temp.Clone();
RustFfiApi.rustffi_get_version_free(temp);
return ver ;
}
}
But the C# program crashes when it runs rustffi_get_version_free(temp)
. 但是当它运行
rustffi_get_version_free(temp)
时,C#程序崩溃了。 How to free the forgotten string memory in C#? 如何在C#中释放被遗忘的字符串内存? What should be passed back to Rust for deallocation?
什么应该传递回Rust进行解除分配?
Instead of defining string
as the argument in the C# extern, I changed it to pointer
. 我没有将
string
定义为C#extern中的参数,而是将其更改为pointer
。
[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version")]
public static extern System.IntPtr rustffi_get_version();
[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version_free")]
public static extern void rustffi_get_version_free(System.IntPtr s);
public static string GetVersion()
{
System.IntPtr tempPointer = RustFfiApi.rustffi_get_version();
string tempString = Marshal.PtrToStringAnsi(tempPointer);
string ver = (string)tempString.Clone();
RustFfiApi.rustffi_get_version_free(tempPointer);
return ver ;
}
The IntPtr
from rustffi_get_version
can be successfully converted to a C# managed string type. 来自
rustffi_get_version
的IntPtr
可以成功转换为C#托管字符串类型。 tempString
and ver
are good. tempString
和ver
都很好。
When rustffi_get_version_free(tempPointer)
runs, it throws an exception saying stack unbalanced : 当
rustffi_get_version_free(tempPointer)
运行时,它会抛出一个异常,表示堆栈不平衡 :
A call to PInvoke function 'rustFfiLibrary!rustFfiLibrary.RustFfiApi::rustffi_get_version_free' has unbalanced the stack.
调用PInvoke函数'rustFfiLibrary!rustFfiLibrary.RustFfiApi :: rustffi_get_version_free'使堆栈失去平衡。 This is likely because the managed PInvoke signature does not match the unmanaged target signature.
这很可能是因为托管PInvoke签名与非托管目标签名不匹配。 Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。
sizeof(IntPtr)
and sizeof(char *)
are both 4 on my system. sizeof(IntPtr)
和sizeof(char *)
在我的系统上都是4。 Plus, IntPtr
works for return value; 另外,
IntPtr
工作价格为返回值; why doesn't it work as an input parameter? 为什么它不能作为输入参数?
extern "C" fn
in Rust means the function uses the C calling convention. Rust中的
extern "C" fn
意味着该函数使用C调用约定。 C# expects P/Invoke functions to use the stdcall calling convention by default. C#期望P / Invoke函数默认使用stdcall调用约定。
You can tell C# to use the C calling convention: 您可以告诉C#使用C调用约定:
[DllImport("rustffilib.dll", CallingConvention = CallingConvention.Cdecl)]
Alternatively, you could use extern "stdcall" fn
on the Rust side. 或者,您可以在Rust端使用
extern "stdcall" fn
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.