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

Why does a panic while panicking result in an illegal instruction?

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

use scopeguard::defer; // 1.1.0

fn main() {
    defer!{ panic!() };
    defer!{ panic!() };
}

我知道这通常发生在 Drop 实现在从先前的恐慌中解除时出现恐慌,但为什么它会导致程序发出非法指令?这听起来像是代码已损坏或跳到了无意的地方。我认为这可能取决于系统或代码生成,但我在各种平台上进行了测试,它们都出于相同的原因发出类似的错误:

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

此行为是有意的。

来自 comment by Jonas Schievink in Why does panicking in a Drop impl cause SIGILL?:

It calls intrinsics::abort(), which LLVM turns into a ub2 instruction, which is illegal, thus SIGILL

我找不到任何关于如何处理双重恐慌的文档,但是 std::intrinsics::abort() 的一段符合这种行为:

The current implementation of intrinsics::abort is to invoke an invalid instruction, on most platforms. On Unix, the process will probably terminate with a signal like SIGABRT, SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise behaviour is not guaranteed and not stable.

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

结束

在 x86 上选择的非法指令是 UD2(我认为上面的评论有错字)a.k.a。矛盾的是,undefined instruction 被保留并记录为不是指令。所以没有腐败或无效跳转,只是一种快速而响亮的方式告诉 OS 出了什么问题。