rustnomicon 包含以下示例:
#[no_mangle]
extern "C" fn assert_nonzero(input: u32) {
assert!(input != 0)
}
如果使用参数
调用assert_nonzero
,则运行时保证(安全)中止该进程,无论是否使用0
进行编译。panic=abort
另一方面,Rust Reference 声称:
行为被视为未定义:[...]使用错误的调用 ABI 调用函数或从具有错误的展开 ABI 的函数展开。
这两种说法对我来说似乎是矛盾的。
assert_nonzero
具有 C
ABI,但可以从 Rust 恐慌中解脱出来。那么这是保证(安全)中止,还是UB?不可能两者兼而有之。
Chayim Friedman 在另一个问题中善意地建议这确实是 UB。
Rustnomicon 是否已经过时了,还是我误解了什么?
更一般地说:跨越 FFI 边界的 Rust 恐慌何时被视为未定义行为?
-unwind
ABI 的 RFC:
现有 ABI 字符串行为的更改
在此 RFC 之前,任何跨越
边界的展开操作,无论是来自 Rust 函数的extern "C"
“转义” 使用panic!
定义或通过从另一种语言输入 Rust 来定义 通过使用extern "C"
声明的入口点,导致未定义 行为。extern "C"
此 RFC 保留了大部分未定义的行为,但有一个例外: 对于
运行时,panic=unwind
将导致panic!
如果 否则会从用abort
. 定义的函数中“逃逸”extern "C"
此更改将应用于除
之外的所有 ABI 字符串, 比如"Rust"
。"system"
所以看起来这曾经是UB,但是在这个RFC被接受之后,这不再是UB并且肯定会中止。
我不知道我们是否可以说该引用已过时,因为我们可以说我们只是不会因
extern "C"
Rust 函数的恐慌而放松(而是中止)。