Rust Win32 FFI:违反用户模式数据执行保护 (DEP)
Rust Win32 FFI: User-mode data execution prevention (DEP) violation
我正在尝试将 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));
}
}
在 Rust 方面,设备确实可以工作,但在 C 方面,当 FFMEPG 调用 ID3D11DeviceContext_QueryInterface
应用程序崩溃并出现以下错误:Exception 0xc0000005 encountered at address 0x7ff9fb99ad38: User-mode data execution prevention (DEP) violation at location 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, [=11=]xfd
你有任何进一步调试的指示吗?
编辑: 我做了一个最小复制样本。有趣的是,这不会导致 DEP 违规,而只会导致段错误。
C端:
int test_ffi(ID3D11Device *device){
ID3D11DeviceContext *context;
device->lpVtbl->GetImmediateContext(device, &context);
if (!context) return 1;
return 0;
}
在 Rust 方面:
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
根据 https://github.com/microsoft/windows-rs/issues/1710#issuecomment-1111522946,我的错误是我正在转换结构,而我应该做的是转换引用:
let f2 : &mut ID3D11Device = transmute_copy(&mut device); //Transmuting the WinAPI into a bindgen ID3D11Device
test_ffi(f2);
我正在尝试将 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));
}
}
在 Rust 方面,设备确实可以工作,但在 C 方面,当 FFMEPG 调用 ID3D11DeviceContext_QueryInterface
应用程序崩溃并出现以下错误:Exception 0xc0000005 encountered at address 0x7ff9fb99ad38: User-mode data execution prevention (DEP) violation at location 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, [=11=]xfd
你有任何进一步调试的指示吗?
编辑: 我做了一个最小复制样本。有趣的是,这不会导致 DEP 违规,而只会导致段错误。
C端:
int test_ffi(ID3D11Device *device){
ID3D11DeviceContext *context;
device->lpVtbl->GetImmediateContext(device, &context);
if (!context) return 1;
return 0;
}
在 Rust 方面:
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
根据 https://github.com/microsoft/windows-rs/issues/1710#issuecomment-1111522946,我的错误是我正在转换结构,而我应该做的是转换引用:
let f2 : &mut ID3D11Device = transmute_copy(&mut device); //Transmuting the WinAPI into a bindgen ID3D11Device
test_ffi(f2);