为什么恐慌时恐慌会导致非法指令?

kmd*_*eko 3 panic rust illegal-instruction

考虑以下故意导致双重恐慌的代码:

use scopeguard::defer; // 1.1.0

fn main() {
    defer!{ panic!() };
    defer!{ panic!() };
}
Run Code Online (Sandbox Code Playgroud)

我知道当Drop实现在从之前的恐慌中恢复时出现恐慌时,通常会发生这种情况,但为什么它会导致程序发出非法指令呢?听起来代码已损坏或意外跳转到某个地方。我认为这可能与系统或代码生成相关,但我在各种平台上进行了测试,它们都因相同的原因而发出类似的错误:

这是怎么回事?这是什么原因造成的?

kmd*_*eko 7

这种行为是有意为之的。

来自Jonas Schievink 在Why doespanicking in a Drop impl Causes SIGILL?中的评论

它调用intrinsics::abort(),LLVM 将其转换为一条ub2指令,这是非法的,因此 SIGILL

我找不到任何有关如何处理双重恐慌的文档,但有一段std::intrinsics::abort()与此行为相符:

当前的实现intrinsics::abort是在大多数平台上调用无效指令。在 Unix 上,进程可能会以SIGABRTSIGILLSIGTRAPSIGSEGV等信号终止SIGBUS。精确的行为无法保证且不稳定。

奇怪的是,这种行为与调用不同std::process::abort(),后者总是以 终止SIGABRT

x86 上选择的非法指令是UD2(我认为上面评论中的拼写错误)又名未定义指令,它被矛盾地保留并记录为不是指令。因此,不存在损坏或无效跳转,只是一种快速而响亮的方式告诉操作系统出现了严重错误。

  • 我的假设是,在双重恐慌期间使用“core::intrinsics::abort”(“std::intrinsics::abort”是其重新导出),因为即使与“#![no_std]”一起使用,它也必须工作`,并且 `core::instrinsics::abort` 使用非法指令,因为 `core` 库无法使用操作系统的功能。 (5认同)