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.
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.