抛出异常的责任是谁的?操作系统还是进程?

17

从操作系统的角度来看,异常是如何工作的?

作为一名C++程序员,我能够理解异常的工作原理。当抛出异常时,堆栈开始展开,每个激活记录都有机会捕获和处理异常。

但首先抛出异常的责任是谁呢?

  1. 是操作系统向进程发送触发信号,告诉它进入“异常处理状态”吗?
  2. 还是进程在自己的程序空间中调用和处理异常,对操作系统保密?

以下是两个崩溃的程序,说明了我的不确定性。

int main(){

    int i = 1/0; //did the OS tell the process to end?

    return 0;
}

#include <exception>

int main(){

    throw 11;  //did the process tell the OS it needs to end?

    return 0;
}

1
快速回答:C++异常完全由进程驱动。但是我对如何确切地处理异常的答案还不够了解。编辑:在您的第一种情况中,进程接收到一个信号,该信号可以转换为C++异常。 - André Puel
你的两个示例都没有发生崩溃。 - BЈовић
1
@BЈовић 我认为Xploit所说的崩溃是指以非0错误代码退出。 - André Puel
1
第二个调用abort(在标准库中有定义),第一个是硬件信号。 - BЈовић
@BЈовић 对不起,没有达到返回0。那就是我的意思。 - Trevor Hickey
3个回答

12

C++异常是语言的一部分,由语言标准定义,并由编译器和运行时库实现。CPU检测到的其他Undefined Behavior异常,如除零或取消引用空指针,都是语言标准中的例子。这些在处理器术语中称为faults,例如,在x86上触发一个fault handler,然后由操作系统服务。操作系统可以选择向引起该故障的进程报告该故障,在Unix上使用signals进行处理。如果您的进程已为SIGSEGV安装了signal handler,则可以处理进程取消引用空指针时CPU生成的故障...这个机制与语言定义的C++异常是独立的。

在您的示例中,当C++程序throws异常时,这完全由编译器生成的代码和语言运行时库处理,无需内核调用,也没有由处理器生成的硬件故障。


这个答案还可以补充一点,就是标准程序/语言异常的LLVM实现。抽象而且格式很好。 - Red XIII

8
你在谈论两种完全不同的异常处理过程。
第一种由操作系统提供。在Windows中,你可以使用__try__except来处理它们。
第二种是由C++编译器提供的,与操作系统无关。

4
+1 我还要补充一点,C++ 异常具有特定于平台的实现,通常基于操作系统提供的功能。 - lapk
@lapk的评论似乎直接与答案相矛盾:“基于”!=“以任何方式不涉及”。需要一些澄清。 - Felix Dombek
@FelixDombek 我的意思是,C++规范声明了C++异常的操作方式,与操作系统无关。如果编译器选择利用一些操作系统设施,它可以自由地这样做,但这是一个实现细节 - 你不能依赖它。 - Mark Ransom

7
由于我只知道一两个用C++编写的操作系统,而我更了解的那个根本不使用异常,因此这基本上排除了操作系统抛出异常的可能性。
三个主要的操作系统(Linux、Windows、MacOS X)以及所有形式的Unix(AIX、Solaris、HP-UX等)都是用C语言编写的,并且几乎所有其他商业可用的操作系统都不是用汇编语言编写的,因此无法抛出C++类型的异常[这并不意味着没有软件驱动的异常,只是它们不是你在C++中使用"try/catch"捕获的异常,需要进行某种翻译]。
在第一个示例中,操作系统肯定会参与[在我所知道的所有操作系统中],因为在具有除法功能的所有机器上,除以零会导致硬件异常,因此操作系统将需要参与。此外,无论你用C++、C还是汇编语言编写相同的代码,它们将以相同的方式编译和失败。对于大多数操作系统,它们将向程序发送信号,但由于你没有处理信号的代码,你的代码很可能会简单地中止运行,并告诉操作系统发生了一些奇怪的事情,它已经放弃了,甚至不费力地解开堆栈。
在第二种情况下,操作系统根本没有涉及。在调用main函数时,有一个“try-catch”块,它说:“哎呀,有人扔了一些东西,没有被捕获,让我们退出”。其中唯一涉及操作系统的部分是“退出这个进程”,当然需要由操作系统完成,尽管我相信在大多数操作系统中,从'应用程序的起始地址'返回也将产生同样的效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接