Rust program works on dev build but segfaults on release build

754 Views Asked by At

I've written a wrapper for a camera library in Rust that commands and operates a 16-bit camera, and also saves an image to file, using bindgen. Once I command an exposure to start (basically telling the camera to take an image), I can grab the image using a function of the form:

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

In C++, this function was:

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

In C++, I can pass in a buffer of the form imgdata = new unsigned char[length_buffer] and the function would fill the buffer with image data from the camera.

In Rust, similarly, I can pass in a mut_ptr of a buffer in the form of a Vec: let mut buffer: Vec<u16> = vec![0u16; length_buffer].

Currently, the way I have structured the code is that there is a main struct, with settings such as the width and height of image, the camera handle, and others, including the image buffer. The struct has been initialized as a mut as:

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

And when passing it to the GetQHYCCDSingleFrame function, I pass it accordingly:

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

This code works perfectly when I build the program with cargo build or cargo build --release and run using cargo run or cargo run --release. The program starts the exposure, waits until the exposure is done, and then "gets" the frame and populates the buffer with image data correctly.

However, initially when I was writing the program, I had mistakenly declared the GetQHYCCDSingleFrame function as:

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

(Note the change in imgdata type from *mut u16 to &mut [u16]).

When I passed in the same previous buffer as a slice and not a pointer:

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

the program worked perfectly when I built it with cargo build and ran using cargo run (dev build with 0 optimizations). The function and call worked, and the image buffer populated. However, the program segfaulted at GetQHYCCDSingleFrame when I built it using cargo build --release or ran it using cargo run --release (release build with opt-level = 3).

Using rust-gdb, the segfault error was:

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.

I haven't had much experience with Rust optimizations, and don't quite get what optimizations Rust is doing to cause the program to segfault when it runs perfectly with no optimizations. I do understand the correct thing to do is to send in a mut_ptr as I do now, and everything works, but looking back, I would like to understand why the previous erroneous program worked but only in dev build and not release build? Is there a possibility it might be understanding the context in the C++ code the requirement there? Or is it something else going on?

If any more information might help understand, I'd be more than happy to provide that as well. Thanks!

1

There are 1 best solutions below

0
Angelicos Phosphoros On

Your FFI-function signature is invalid because you use invalid ABI:

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

You should read about FFI first.

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

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

By default, Rust uses "C" ABI for external functions but you function should use stdcall ABI (assuming by your C++ code). You can read more about this.

E.g.

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