fraiser
fraiser

Reputation: 969

Creating a c_void pointer in Rust

I have a function with input of type ptr::NonNull<c_void>. Usually this input is provided by C code. Legitimate input is of type: &(int){5}.

However, I need to create some inputs in Rust. So I did the following:

let i = 5;
let data = &i as *const u32;
ptr::NonNull::new_unchecked(data as *mut _)

In case of legit input from C code, the following block executes:

ptr::NonNull::new_unchecked(x.data as *mut _)

where x.data comes from a struct, where x is of type X:

#[repr(C)]
pub struct X {
    data: *const c_void,
}

For reference, the code together looks something like:

if x.data.is_null() {
    let i = 5;
    let data = &i as *const u32;
    ptr::NonNull::new_unchecked(data as *mut _)
} else {
    // x.data is specified in C code through FFI as &(int){5}
    ptr::NonNull::new_unchecked(x.data as *mut _)
}

However, when I attempt to dereference the value at a later stage, for the else branch, I get 5 as expected. But for the if branch, I get a large garbage value. I'm assuming it has to do with how I'm creating the raw pointer in Rust.

Upvotes: 1

Views: 4939

Answers (1)

Sean
Sean

Reputation: 123

In your if branch you are creating a locally scoped variable i, getting a pointer (reference) to it and passing that reference to new_unchecked which doesn't copy your data, it just encapsulates the pointer that you then pass outside of your scope.

Later in the program you try to access the data which is no longer in scope and thus you get unspecified data.

Try defining the data in a Box and use into_raw() to get your pointer

EDIT: Actually, something like this may be better:

let val = if x.data.is_null() {
    5
} else {
    *x.data
};
let data = &val as *const u32;
ptr::NonNull::new_unchecked(data as *mut _)

which takes the allocation out of the enclosing block.

Upvotes: 4

Related Questions