从Rust调用C++虚方法执行成功后触发Access violation错误
Rust调用C++虚方法后触发访问违例的解决方法
你遇到的0xC0000005访问违例,核心原因是C++虚函数调用必须传递this指针作为第一个参数,但当前Rust代码没有正确处理这一机制,导致函数执行后栈帧被破坏,触发内存访问错误。
问题代码分析
C++中虚函数sum的实际调用签名是:
int sum(Calculate* this, int a, int b);
但你在Rust的CalculateVtbl里定义的sum函数缺少了this参数。调用((*self.vtbl).sum)(a, b)时,相当于把5错误地当作this指针传入,6作为a参数,原本的b参数位置是垃圾值——虽然巧合算出了11,但栈平衡被彻底打破,函数返回时必然触发访问违例。
修复后的代码
修改Rust端的虚表定义和方法调用逻辑,正确传递this指针:
#[link(name = "testvirtual")] extern "C" { fn get_numbers() -> *mut Calculate; } #[repr(C)] pub struct CalculateVtbl { // 第一个参数必须是C++对象的this指针 pub sum: unsafe extern "C" fn(this: *const Calculate, a: i32, b: i32) -> i32, } #[repr(C)] pub struct Calculate { pub vtbl: *const CalculateVtbl, } impl Calculate { #[inline(always)] pub unsafe fn sum(&self, a: i32, b: i32) -> i32 { // 传递当前对象的指针作为this参数 ((*self.vtbl).sum)(self, a, b) } } #[no_mangle] pub unsafe extern "C" fn execute() { let a = get_numbers(); let val = (*a).sum(5, 6); println!("val = {val}"); }
额外注意事项
- 结构体布局一致性:
#[repr(C)]已经保证Rust结构体和C结构体的内存布局完全匹配,C虚基类的第一个成员就是虚表指针,和Rust的Calculate定义对齐。 - 内存管理:如果需要释放C对象,务必在C代码中导出一个销毁函数:
然后在Rust中调用该函数,避免内存泄漏。extern "C" __declspec(dllexport) void destroy_calculate(Calculate* obj) { delete obj; } - 调用约定:x86架构下C++虚函数默认使用
thiscall,通过extern "C"声明后,clang会自动调整为兼容的调用约定,无需额外修改。
内容的提问来源于stack exchange,提问作者Sreyas
相关产品推荐
相关产品推荐

