3

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

use scopeguard::defer; // 1.1.0

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

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

  • Linux:

    thread panicked while panicking. aborting.
    Illegal instruction (core dumped)
    
  • 窗户(带cargo run):

    thread panicked while panicking. aborting.
    error: process didn't exit successfully: `target\debug\tests.exe` (exit code: 0xc000001d, STATUS_ILLEGAL_INSTRUCTION)
    
  • 锈游乐场:

    thread panicked while panicking. aborting.
    timeout: the monitored command dumped core
    /playground/tools/entrypoint.sh: line 11:     8 Illegal instruction     timeout --signal=KILL ${timeout} "$@"
    

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

4

1 回答 1

6

这种行为是有意的。

来自Jonas Schievink为什么 Drop impl 中的恐慌会导致 SIGILL 中的评论?

它调用intrinsics::abort(),LLVM 变成一条ub2指令,这是非法的,因此 SIGILL

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

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

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

x86 上选择的非法指令是UD2(我认为上面的评论中有错字)又名未定义的指令,自相矛盾地被保留并记录为不是指令。所以没有损坏或无效跳转,只是一种快速而响亮的方式告诉操作系统出现了非常错误的问题。

于 2021-09-26T01:13:49.877 回答