4

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Kornel
  • 97,764
  • 37
  • 219
  • 309

1 Answers1

5

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • In this case, `repr(C)` would be enough, since `NonNull` is not a newtype, however, since it's neither marked as `repr(C)` nor as `repr(transparent)` it isn't safe. – Tim Diekmann Mar 20 '18 at 22:14
  • @Tim would you share why you say its not a newtype? it's a struct of a single field, which is the key component of a newtype AFAIK. – Shepmaster Mar 20 '18 at 22:31
  • I assumed newtypes are structs of the form `struct Foo(Bar);` but correct me, if I got this wrong. At least in all literature I read so far, the term "Newtype" was in this context. – Tim Diekmann Mar 20 '18 at 23:45