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
实现在从之前的恐慌中恢复时出现恐慌时,通常会发生这种情况,但为什么它会导致程序发出非法指令呢?听起来代码已损坏或意外跳转到某个地方。我认为这可能与系统或代码生成相关,但我在各种平台上进行了测试,它们都因相同的原因而发出类似的错误:
Linux:
use scopeguard::defer; // 1.1.0
fn main() {
defer!{ panic!() };
defer!{ panic!() };
}
Run Code Online (Sandbox Code Playgroud)
窗口(带有cargo run
):
thread panicked while panicking. aborting.
Illegal instruction (core dumped)
Run Code Online (Sandbox Code Playgroud)
铁锈游乐场:
thread panicked while panicking. aborting.
error: process didn't exit successfully: `target\debug\tests.exe` (exit code: 0xc000001d, STATUS_ILLEGAL_INSTRUCTION)
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?这是什么原因造成的?
这种行为是有意为之的。
来自Jonas Schievink 在Why doespanicking in a Drop impl Causes SIGILL?中的评论 :
它调用
intrinsics::abort()
,LLVM 将其转换为一条ub2
指令,这是非法的,因此 SIGILL
我找不到任何有关如何处理双重恐慌的文档,但有一段std::intrinsics::abort()
与此行为相符:
当前的实现
intrinsics::abort
是在大多数平台上调用无效指令。在 Unix 上,进程可能会以SIGABRT
、SIGILL
、SIGTRAP
或SIGSEGV
等信号终止SIGBUS
。精确的行为无法保证且不稳定。
奇怪的是,这种行为与调用不同std::process::abort()
,后者总是以 终止SIGABRT
。
x86 上选择的非法指令是UD2
(我认为上面评论中的拼写错误)又名未定义指令,它被矛盾地保留并记录为不是指令。因此,不存在损坏或无效跳转,只是一种快速而响亮的方式告诉操作系统出现了严重错误。