Rust与C# FFI互调时调用C#函数抛出System.AccessViolationException
Rust与C# FFI回调异常修复方案
错误根源
- 参数类型不匹配:C#传递的是函数指针(
IntPtr),但Rust函数错误地将参数声明为&i8,导致内存解析完全错误,直接触发访问违规。 - 类型转换错误:用
clone()和transmute处理函数指针的方式不符合C调用约定,进一步加剧内存访问问题。
修正后的代码
C# 代码
public class Program { [DllImport("D:\\Misc. CSharp\\NativeTesting\\Rust\\target\\debug\\test.dll")] public static extern void Test(IntPtr function); public static void TestFunction() { Console.WriteLine("Test!"); } public delegate void TestDelegate(); public static void Main() { // 保留委托引用,避免被GC意外回收 TestDelegate callback = TestFunction; Test(Marshal.GetFunctionPointerForDelegate(callback)); Console.WriteLine("Done"); } }
Rust 代码(推荐写法)
#[no_mangle] pub extern "C" fn Test(logger: extern "C" fn()) { // 直接调用符合C调用约定的函数指针 logger(); }
Rust 代码(原始指针兼容写法)
如果需要更灵活的指针处理,也可以用原始指针转换:
#[no_mangle] pub extern "C" fn Test(logger: *const ()) { unsafe { // 将原始指针转换为C调用约定的函数指针 let callback: extern "C" fn() = std::mem::transmute(logger); callback(); } }
关键说明
- 必须用
extern "C"修饰Rust中的函数指针,确保和C# P/Invoke的默认调用约定一致。 - 显式保留C#委托的引用是FFI回调的最佳实践,即使静态方法的委托被回收概率低,也能避免潜在的内存访问问题。
- 参数类型严格匹配是FFI通信的核心,任何类型不匹配都会导致内存错误或程序崩溃。
内容的提问来源于stack exchange,提问作者Big_Bad_E
相关产品推荐
相关产品推荐

