为什么恐慌时恐慌会导致非法指令?
Why does a panic while panicking result in an illegal instruction?
考虑以下故意导致双重恐慌的代码:
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)
Rust 游乐场:
thread panicked while panicking. aborting.
timeout: the monitored command dumped core
/playground/tools/entrypoint.sh: line 11: 8 Illegal instruction timeout --signal=KILL ${timeout} "$@"
这是怎么回事?这是什么原因造成的?
此行为是有意的。
来自 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 出了什么问题。
考虑以下故意导致双重恐慌的代码:
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)
Rust 游乐场:
thread panicked while panicking. aborting. timeout: the monitored command dumped core /playground/tools/entrypoint.sh: line 11: 8 Illegal instruction timeout --signal=KILL ${timeout} "$@"
这是怎么回事?这是什么原因造成的?
此行为是有意的。
来自 comment by Jonas Schievink in Why does panicking in a Drop impl cause SIGILL?:
It calls
intrinsics::abort()
, which LLVM turns into aub2
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 likeSIGABRT
,SIGILL
,SIGTRAP
,SIGSEGV
orSIGBUS
. The precise behaviour is not guaranteed and not stable.
奇怪的是,这种行为与调用 std::process::abort()
不同,后者总是以 SIGABRT
.
在 x86 上选择的非法指令是 UD2
(我认为上面的评论有错字)a.k.a。矛盾的是,undefined instruction 被保留并记录为不是指令。所以没有腐败或无效跳转,只是一种快速而响亮的方式告诉 OS 出了什么问题。