Rust Win32 FFI:用户模式数据执行预防(DEP)违规

发布于 2025-01-24 14:24:30 字数 4539 浏览 3 评论 0原文

我正在尝试将ID3D11DEVICE实例从Rust到C FFI库(FFMPEG)。

我制作了此示例代码:

pub fn create_d3d11_device(&mut self, device: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11Device>, context: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11DeviceContext>) {
            let av_device : Box<AVBufferRef> = self.alloc(HwDeviceType::D3d11va);
            unsafe {
                let device_context = Box::from_raw(av_device.data as *mut AVHWDeviceContext);
                let mut d3d11_device_context = Box::from_raw(device_context.hwctx as *mut AVD3D11VADeviceContext);
                d3d11_device_context.device = device.as_mut() as *mut _;
                d3d11_device_context.device_context = context.as_mut() as *mut _;
                let avp = Box::into_raw(av_device);
                av_hwdevice_ctx_init(avp);
                self.av_hwdevice = Some(Box::from_raw(avp));
            }
        }

在生锈方面,设备确实可以工作,但是在C侧,当FFMEPG调用ID3D11DeviceContext_QueryInterface该应用程序崩溃的错误:exception 0xc0000005在地址0x7ff9fb9999ad38上遇到的exception 0xc0000005位置的用户模式数据执行预防(DEP)违规0x7ff9fb99ad38

地址实际上是QueryInterface的LPVTBL的指针,如下所示: ”

地址的拆卸看起来也是正确的另一个调试会话):

(lldb) disassemble --start-address 0x00007ffffdf3ad38
    0x7ffffdf3ad38: addb   %ah, 0x7ffffd(%rdi,%riz,8)
    0x7ffffdf3ad3f: addb   %al, (%rax)
    0x7ffffdf3ad41: movabsl -0x591fffff80000219, %eax
    0x7ffffdf3ad4a: outl   %eax, $0xfd

您有什么指针要进一步调试吗?

编辑:我做了一个最小的复制样本。有趣的是,这并不会导致DEP违规,而只是违反了DEP违规。

在C侧:

int test_ffi(ID3D11Device *device){
    ID3D11DeviceContext *context;
    device->lpVtbl->GetImmediateContext(device, &context);
    if (!context) return 1;
    return 0;
}

在生锈的一面:

unsafe fn main_rust(){
    let mut device = None;
    let mut device_context = None;
    let _ = match windows::Win32::Graphics::Direct3D11::D3D11CreateDevice(None, D3D_DRIVER_TYPE_HARDWARE, OtherHinstance::default(), D3D11_CREATE_DEVICE_DEBUG, &[], D3D11_SDK_VERSION, &mut device, std::ptr::null_mut(), &mut device_context) {
        Ok(e) => e,
        Err(e) => panic!("Creation Failed: {}", e)
    };
    let mut device = match device {
        Some(e) => e,
        None => panic!("Creation Failed2")
    };
    let mut f2 : ID3D11Device = transmute_copy(&device); //Transmuting the WinAPI into a bindgen ID3D11Device
    test_ffi(&mut f2);
}

bindgen build.rs:

extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system bzip2
    // shared library.
    println!("cargo:rustc-link-lib=ffi_demoLIB");
    println!("cargo:rustc-link-lib=d3d11");

    // Tell cargo to invalidate the built crate whenever the wrapper changes
    println!("cargo:rerun-if-changed=library.h");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("library.h")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .blacklist_type("_IMAGE_TLS_DIRECTORY64")
        .blacklist_type("IMAGE_TLS_DIRECTORY64")
        .blacklist_type("PIMAGE_TLS_DIRECTORY64")
        .blacklist_type("IMAGE_TLS_DIRECTORY")
        .blacklist_type("PIMAGE_TLS_DIRECTORY")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

可以通过这里找到完整的回购: https://github.com/theelixzammuto/demo-ffi

I'm trying to pass a ID3D11Device instance from Rust to a C FFI Library (FFMPEG).

I made this sample code:

pub fn create_d3d11_device(&mut self, device: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11Device>, context: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11DeviceContext>) {
            let av_device : Box<AVBufferRef> = self.alloc(HwDeviceType::D3d11va);
            unsafe {
                let device_context = Box::from_raw(av_device.data as *mut AVHWDeviceContext);
                let mut d3d11_device_context = Box::from_raw(device_context.hwctx as *mut AVD3D11VADeviceContext);
                d3d11_device_context.device = device.as_mut() as *mut _;
                d3d11_device_context.device_context = context.as_mut() as *mut _;
                let avp = Box::into_raw(av_device);
                av_hwdevice_ctx_init(avp);
                self.av_hwdevice = Some(Box::from_raw(avp));
            }
        }

On the Rust side the Device does work, but on the C side, when FFMEPG calls ID3D11DeviceContext_QueryInterface the app crashes with the following error: Exception 0xc0000005 encountered at address 0x7ff9fb99ad38: User-mode data execution prevention (DEP) violation at location 0x7ff9fb99ad38

The address is actually the pointer for the lpVtbl of QueryInterface, like seen here:

The disassembly of the address also looks correct (this is done on an another debugging session):

(lldb) disassemble --start-address 0x00007ffffdf3ad38
    0x7ffffdf3ad38: addb   %ah, 0x7ffffd(%rdi,%riz,8)
    0x7ffffdf3ad3f: addb   %al, (%rax)
    0x7ffffdf3ad41: movabsl -0x591fffff80000219, %eax
    0x7ffffdf3ad4a: outl   %eax, $0xfd

Do you have any pointer to debug this further?

EDIT: I made a Minimal Reproducion Sample. Interestingly this does not causes a DEP Violation, but simply a Segfault.

On the C side:

int test_ffi(ID3D11Device *device){
    ID3D11DeviceContext *context;
    device->lpVtbl->GetImmediateContext(device, &context);
    if (!context) return 1;
    return 0;
}

On the Rust side:

unsafe fn main_rust(){
    let mut device = None;
    let mut device_context = None;
    let _ = match windows::Win32::Graphics::Direct3D11::D3D11CreateDevice(None, D3D_DRIVER_TYPE_HARDWARE, OtherHinstance::default(), D3D11_CREATE_DEVICE_DEBUG, &[], D3D11_SDK_VERSION, &mut device, std::ptr::null_mut(), &mut device_context) {
        Ok(e) => e,
        Err(e) => panic!("Creation Failed: {}", e)
    };
    let mut device = match device {
        Some(e) => e,
        None => panic!("Creation Failed2")
    };
    let mut f2 : ID3D11Device = transmute_copy(&device); //Transmuting the WinAPI into a bindgen ID3D11Device
    test_ffi(&mut f2);
}

The bindgen build.rs:

extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system bzip2
    // shared library.
    println!("cargo:rustc-link-lib=ffi_demoLIB");
    println!("cargo:rustc-link-lib=d3d11");

    // Tell cargo to invalidate the built crate whenever the wrapper changes
    println!("cargo:rerun-if-changed=library.h");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("library.h")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .blacklist_type("_IMAGE_TLS_DIRECTORY64")
        .blacklist_type("IMAGE_TLS_DIRECTORY64")
        .blacklist_type("PIMAGE_TLS_DIRECTORY64")
        .blacklist_type("IMAGE_TLS_DIRECTORY")
        .blacklist_type("PIMAGE_TLS_DIRECTORY")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

The Complete Repo can be found over here: https://github.com/TheElixZammuto/demo-ffi

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

墨落成白 2025-01-31 14:24:30

根据 https://github.com/github.com/microsoft/microsoft/windows-rs/问题/1710#issuecomment-111522946 我的错误是我在扭转结构,而我应该做的是投入参考:

    let f2 : &mut ID3D11Device = transmute_copy(&mut device); //Transmuting the WinAPI into a bindgen ID3D11Device
    test_ffi(f2);

According to https://github.com/microsoft/windows-rs/issues/1710#issuecomment-1111522946 my error was that I was trasmutating the structs, while what I should have done is to cast the references:

    let f2 : &mut ID3D11Device = transmute_copy(&mut device); //Transmuting the WinAPI into a bindgen ID3D11Device
    test_ffi(f2);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文