结构中带有 Option<unsafe fn ...> 的奇怪内存布局

Strange memory layout with Option<unsafe fn ...> within a struct

我正在使用来自 here 的 JNI 定义。我创建了一个 JNINativeInterface_,其中大多数成员初始化为 None。然后我 运行 本机代码使用上述结构的 RegisterNatives 字段。我这样初始化 RegisterNatives 和周围的字段:

SetDoubleArrayRegion: unsafe { transmute(0xdeadbeaf as u64) },
RegisterNatives: Some(register_natives),
UnregisterNatives: unsafe { transmute(0xdeadbeaf as u64) },

register_natives 定义如下(这与库类型完全匹配):

unsafe extern "system" fn register_natives(env: *mut sys::JNIEnv,
                                           clazz: jclass,
                                           methods: *const JNINativeMethod,
                                           nMethods: jint) -> jint {
    unimplemented!()
}

使用结构段错误的本机代码(并且似乎得到一个空指针而不是 register_natives)。

结构的相关部分在 GDB 下看起来像这样:

0x7ffcf5f4a5b8: 0x0 0x0 0x0 0x0
0x7ffcf5f4a5c8: 0xdeadbeaf  0x0 0x43fd9950  0x55ea
0x7ffcf5f4a5d8: 0xdeadbeaf  0x0 0x0 0x0
0x7ffcf5f4a5e8: 0x0 0x0 0x0 0x0

我很困惑我到底在看什么,因为我期待 0xdeadbeaf ,后跟一个 64 位指针,然后是 0xdeadbeaf,但正如你所看到的,这不是我得到的。我关于选项将如何在幕后表示的假设是否错误?为什么 bindgen/the 上述库似乎认为 Option 会导致兼容的接口?

[...] I was expecting 0xdeadbeaf, followed by a 64 bit pointer, followed by 0xdeadbeaf, but as you can see that is not what I get.

我们一定看到的不是同一件事,因为我确实看到了。

0x7ffcf5f4a5c8: 0xdeadbeaf  0x0 0x43fd9950  0x55ea
0x7ffcf5f4a5d8: 0xdeadbeaf  0x0 0x0 0x0

每个十六进制数都是一个 32 位整数,所以你必须取两个来组成一个 64 位整数。第一个是 0x00000000deadbeaf,第二个是 0x000055ea43fd9950(大概是你的 register_natives 函数),第三个也是 0x00000000deadbeaf。 (从地址上也是"obvious":一个64位整数占8个字节,所以需要两个占0x10个字节,所以每行有两个64位整数。)

程序段错误的原因可能是因为让恐慌通过外部代码解除是 undefined behavior。尝试将您的 register_natives 函数更改为不会恐慌的函数。