结构中带有 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
函数更改为不会恐慌的函数。
我正在使用来自 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
函数更改为不会恐慌的函数。