【问题标题】:Why does a panic while panicking result in an illegal instruction?为什么恐慌时恐慌会导致非法指令?
【发布时间】:2021-09-26 01:13:49
【问题描述】:

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

use scopeguard::defer; // 1.1.0

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

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

  • Linux:

    thread panicked while panicking. aborting.
    Illegal instruction (core dumped)
    
  • Windows(带有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} "$@"
    

发生了什么事?这是什么原因造成的?

【问题讨论】:

  • 这是因为你惊慌但抓住它什么的然后惊慌了两次,因为第一次恐慌没有奏效,我猜 rust 做了一个"OK I WILL DO IT MYSELF"

标签: rust panic illegal-instruction


【解决方案1】:

这种行为是有意的。

来自 comment,作者 Jonas Schievink 在Why does panicking in a Drop impl cause SIGILL?

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

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

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

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

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

【讨论】:

  • 我的假设是在双重恐慌期间使用core::intrinsics::abortstd::intrinsics::abort 是重新导出的),因为即使使用#![no_std],它也必须工作,并且core::instrinsics::abort 使用非法指令,因为core 库无法使用操作系统的功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 2019-05-10
  • 1970-01-01
相关资源
最近更新 更多