在 FFI 中使用 ptr::NonNull 是否有效?

Kor*_*nel 4 ffi abi non-nullable rust

Rust 具有ptr::NonNull表示非NULL指针的类型。在 FFI 中使用这种类型是否安全?

是否保证具有相同的二进制表示(忽略非 FFI 上下文,例如Option优化)、对齐、寄存器使用*mut T

例如,我可以实现这个接口:

void call_me_from_c(char *without_nulls) __attribute__((nonnull));
Run Code Online (Sandbox Code Playgroud)

extern "C" fn call_me_from_c(without_nulls: ptr::NonNull<c_char>)
Run Code Online (Sandbox Code Playgroud)

我不希望这会任何事情(除了在误用NULL;时导致 UB 之外),但我希望接口记录该函数需要非NULL参数。

She*_*ter 5

这取决于您正在编译的 Rust 版本。

Rust 1.29 及更高版本

NonNull 现在有repr(transparent),所以只要包裹类型是安全的,就可以安全地在 FFI 中使用。

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

在 Rust 1.29 之前

不会用它来做这样的事情。主要原因是由于它的定义

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

更具体地说,我担心定义中没有的内容:(#[repr(transparent)]强调我的):

具有此表示形式的结构与单个非零大小的字段具有相同的布局和 ABI

由于将 newtypes 放在由 解决的 FFI 函数中,我经历了错误编译repr(transparent),所以这不仅仅是一个学术练习。