【问题标题】:Rust program works on dev build but segfaults on release build [closed]Rust 程序适用于开发构建,但在发布构建时出现段错误 [关闭]
【发布时间】:2021-11-12 15:10:33
【问题描述】:

我已经为 Rust 中的相机库编写了一个包装器,它命令和操作一个 16 位相机,并且还使用 bindgen 将图像保存到文件中。一旦我命令开始曝光(基本上是告诉相机拍摄图像),我可以使用以下形式的函数抓取图像:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: *mut u16,) -> u32 //(u32 is a retval)

在 C++ 中,这个函数是:

uint32_t STDCALL GetQHYCCDSingleFrame(qhyccd_handle: *handle, ..., uint8_t *imgdata)

在 C++ 中,我可以传入 imgdata = new unsigned char[length_buffer] 形式的缓冲区,该函数将使用来自相机的图像数据填充缓冲区。

类似地,在 Rust 中,我可以以 Vec 的形式传入缓冲区的 mut_ptrlet mut buffer: Vec<u16> = vec![0u16; length_buffer]

目前,我构建代码的方式是有一个主结构,其中包含图像的宽度和高度、相机句柄等设置,包括图像缓冲区。该结构已初始化为mut

let mut main_settings = MainSettings {
width: 9600,
...,
buffer: vec![0u16; length_buffer],
}

当将它传递给GetQHYCCDSingleFrame 函数时,我会相应地传递它:

let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., main_settings.image_buffer.as_mut_ptr()) };

当我使用cargo buildcargo build --release 构建程序并使用cargo runcargo run --release 运行时,此代码完美运行。程序开始曝光,等待曝光完成,然后“获取”帧并用图像数据正确填充缓冲区。

但是,最初在编写程序时,我错误地将 GetQHYCCDSingleFrame 函数声明为:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: &mut [u16],) -> u32 //(u32 is a retval)

(注意 imgdata 类型从 *mut u16 更改为 &mut [u16])。

当我将相同的先前缓冲区作为切片而不是指针传递时:

let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., &mut main_settings.image_buffer) };

当我使用cargo build 构建它并使用cargo run 运行时,该程序运行良好(开发构建具有 0 个优化)。该函数和调用有效,并且填充了图像缓冲区。但是,当我使用 cargo build --release 构建它或使用 cargo run --release 运行它(使用 opt-level = 3 发布构建)时,该程序在 GetQHYCCDSingleFrame 出现了段错误。

使用rust-gdb,段错误是:

Thread 1 "qsc" received signal SIGSEGV, Segmentation fault.
_memmove_sse2_unaligned_erms()
at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:538
538
../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: No such file or directory.

我在 Rust 优化方面没有太多经验,也不太了解 Rust 做了哪些优化来导致程序在没有优化的情况下完美运行时出现段错误。我确实明白正确的做法是像现在一样发送mut_ptr,一切正常,但回首往事,我想了解为什么以前的错误程序有效但只在开发构建而不是发布构建?是否有可能理解 C++ 代码中的上下文以及那里的要求?还是发生了其他事情?

如果有更多信息可能有助于理解,我也很乐意提供。谢谢!

【问题讨论】:

  • 对于你描述的行为(在调试模式下工作,在发布模式下失败),几乎总是因为你的代码有undefined behavior。 Rust 编译器(以及 C 和 C++ 编译器)假定您的代码在执行优化时没有未定义的行为,这意味着如果实际上 is 未定义,某些优化可能会导致奇怪的行为和崩溃行为。

标签: rust ffi rust-cargo rust-bindgen


【解决方案1】:

您的 FFI 函数签名无效,因为您使用了无效的 ABI:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: *mut u16,) -> u32 //(u32 is a retval)

您应该先阅读有关 FFI 的内容。

https://doc.rust-lang.org/nomicon/ffi.html

https://doc.rust-lang.org/reference/items/external-blocks.html

默认情况下,Rust 对外部函数使用“C”ABI,但你的函数应该使用stdcall ABI(假设你的 C++ 代码)。你可以read了解更多。

例如

extern "stdcall" {
 pub fn GetQHYCCDSingleFrame(
   handle: *mut qhyccd_handle,
   w: *mut u32,
   ...,
   imgdata: *mut u16,) -> u32;
}

【讨论】:

    猜你喜欢
    • 2018-06-25
    • 2019-09-26
    • 2021-12-15
    • 1970-01-01
    • 2017-03-13
    • 2010-10-29
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多