从 Rust 调用 C++ 虚拟方法即使在成功执行后也会引发访问冲突错误

问题描述 投票:0回答:1

我正在尝试从 Rust 调用 C++ 对象的虚拟方法。我得到了输出,但执行此方法后,它抛出异常。

Unhandled exception at 0x00000001 in testvirtual.exe: 0xC0000005: Access violation executing location 0x00000001.

这是我的问题的最小重现

#include <iostream>
#include<Windows.h>

struct Calculate{
    virtual int sum(int a, int b) {
        return a + b;
    }
};

extern "C" __declspec(dllexport)  Calculate* get_numbers() {
    Calculate* obj = new Calculate();
    return obj;
}

int main() {
    typedef void(func)();
    auto handle = LoadLibrary(TEXT("testvirtualrs.dll"));
    auto address = (func*)GetProcAddress(handle, "execute");
    (*address)();
    return 0;
}

铁锈:

#[link(name = "testvirtual")]
extern "C" {
    fn get_numbers() -> *mut Calculate;
}

#[repr(C)]
pub struct CalculateVtbl {
    pub sum: unsafe extern "C" fn(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 {
        ((*self.vtbl).sum)(a, b)
    }
}

#[no_mangle]
pub unsafe extern "C" fn execute() {
    let a = get_numbers();
    unsafe {
       let val = (*a).sum(5, 6);
       println!("val = {val}");
    }
}

输出:

val = 11

我还使用 clang 编译器 和 x86 arch。从 Rust 调用方法完成后抛出异常,有点模棱两可,对查找原因没有帮助

c++ rust clang virtual-functions vtable
1个回答
0
投票

在 C++ 中,应该使用

this
指针集来调用非静态方法。名义上,这只是一个隐藏的第一个参数,但在 x86 Windows 上,需要遵循特殊的
thiscall
调用约定。

因此,您需要在 vtable 中创建非常方法 - 以及非虚拟方法 -

extern "thiscall"
:

#[repr(C)]
pub struct CalculateVtbl {
    pub sum: unsafe extern "thiscall" fn(this: *mut Calculate, a: i32, b: i32) -> i32,
}

#[repr(C)]
pub struct Calculate {
    pub vtbl: *const CalculateVtbl,
}

impl Calculate {
    #[inline(always)]
    pub unsafe fn sum(&mut self, a: i32, b: i32) -> i32 {
        ((*self.vtbl).sum)(self, a, b)
    }
}

您可以将此示例放入 Compiler Explorer 中,看看如果将

thiscall
更改回
C
,ECX 会发生什么情况。

© www.soinside.com 2019 - 2024. All rights reserved.