-->

Is it valid to use ptr::NonNull in FFI?

2019-07-21 00:54发布

问题:

Rust has the ptr::NonNull type that represents a non-NULL pointer. Is it safe to use this type in FFI?

Is it guaranteed to have same binary representation (ignoring non-FFI context such as Option optimizations), alignment, register usage as *mut T?

For example, could I implement this interface:

void call_me_from_c(char *without_nulls) __attribute__((nonnull));

with

extern "C" fn call_me_from_c(without_nulls: ptr::NonNull<c_char>)

I don't expect this to do anything (apart from causing UB when misused with NULL ;), but I would like the interface to document that the function requires non-NULL arguments.

回答1:

It depends on what version of Rust you are compiling with.

Rust 1.29 and up

NonNull now has repr(transparent), so it is safe to use in FFI so long as the wrapped type is safe.

#[stable(feature = "nonnull", since = "1.25.0")]
#[repr(transparent)]
pub struct NonNull<T: ?Sized> {
    pointer: NonZero<*const T>,
}

Before Rust 1.29

I would not use it for such. The main reason is due to its definition:

#[stable(feature = "nonnull", since = "1.25.0")]
pub struct NonNull<T: ?Sized> {
    pointer: NonZero<*const T>,
}

More specifically, I'm concerned about what's not in the definition: #[repr(transparent)] (emphasis mine):

Structs with this representation have the same layout and ABI as the single non-zero sized field.

I've experienced miscompilation due to putting newtypes in a FFI function that were solved by repr(transparent), so this isn't just an academic exercise.