Below is a simplified example of the issue I'm facing in larger project. Basically, I have a C library function I need to call that takes a pointer as a parameter. It is an optional parameter that uses NULL to indicate nothingness. Since I'm wrapping the interface in Rust, I of course want to expose that parameter as an Option. However, when I try to take a possibly-null-pointer to the payload of the option and pass that into the function, I get garbage results on the C side. It is pointing to something, but that something is not the right thing.
This only happens when I run with -O passed to the compiler. A debug build prints the expected thing.
It can be reproduced with the following files:
# main.rs
fn main() {
let a: i32 = 7;
test(Some(a));
}
fn test(a: Option<i32>) {
let mut a_ptr = std::ptr::null();
if let Some(v) = a {
a_ptr = &v as _;
};
unsafe {
cfunc(a_ptr);
};
}
extern "C" {
pub fn cfunc(a: *const i32);
}
# func.c
#include <stdint.h>
#include <stdio.h>
void cfunc(const int32_t *b)
{
if (b)
printf("%d\n", *b);
else
printf("Null\n");
}
#!/usr/bin/env bash
# build.sh
gcc -c func.c -o func.o
ar rcs libfunc.a func.o
rustc main.rs -L . -lfunc $1
Then in a shell:
$ ./build.sh ; ./main
7
$ ./build.sh -O; ./main
22014
Without the -O flag, I get 7 which is expected.
With the -O flag, I get nonsense. It is actually a different number each time I run it.
If I take away the null possibility and just pass &a.unwrap() as *const i32
to cfunc() then it works fine. So it seems like somehow the fact that the pointer is sometimes null is screwing things up. It seems I'm somehow getting a pointer to stale data, though not sure how, and why it only shows up in the optimized build. I get no compiler warnings or anything.
Does anyone know what is going wrong here?