当抛出异常的代码链接到使用-fno-exceptions编译的库时会发生什么?

15
具体而言,我想知道GCC在链接使用-fno-exceptions编译的代码时,对于抛出异常行为有什么保证(如果有的话)。
GNU的libstdc++手册在这里给出了以下说明:
“在详细介绍支持-fno-exceptions的库之前,先简单说明使用此标志时会丢失哪些内容:无论编译-fno-exceptions代码是否包含任何trycatch结构,它都会中断试图经过该代码的异常。如果可能有一些会抛出异常的代码,您不应该使用-fno-exceptions。如果有一些使用trycatch的代码,您也不应该使用-fno-exceptions。”
这听起来像是一个类似“你不应该...”的声明。即是未定义的行为。
另一方面,从这个SO问题中的印象是,只要使用-fno-exceptions编译的代码没有throwtrycatch(显然是编译时错误),并且异常从未通过该库的函数传播,一切都是合法的。这是有道理的:只要不影响其功能,为什么应该关心使用-fno-exceptions编译的库是否会抛出异常呢?
我尝试了一些小的实验,并发现如果我使用GCC 7.1.1编译一个简单的程序,在其中一个源文件上使用-fno-exceptions编译,而另一个源文件抛出和捕获异常,所有东西都可以编译、链接和运行。但这并不意味着此行为是保证的;它仍然可能是未定义的。

我之所以这么做是因为我的情况是,我将自己的应用程序代码与使用-fno-exceptions编译的库进行链接,取决于对该库进行何种函数调用,即使在该异常没有通过库的函数传播时,我的代码中抛出异常也会导致立即崩溃。这对我来说很像是库中的一个错误,但我想也许在编译时使用-fno-exceptions是允许这样做的。

GCC的代码生成选项实际参考相对简短地提到了-fexceptions,并没有回答我的问题。有人知道其他参考资料/具有相关经验吗?

更新:我从源代码重新构建了该库,并打开了异常支持。仍然出现崩溃!是时候进行错误报告了。


3
我认为你对于认为-fno-exceptions-fexceptions是兼容的没有明确说明是正确的,但这是暗示。然而(这里有一个疯狂的观点),你确定在抛出异常时没有通过任何库代码吗?显而易见的“隐藏”方式是在堆栈展开时调用(或不调用或误调用)-fno-exceptions析构函数。这只是一个想法。 - Persixty
2
我不认为这就是我的情况,因为即使我将throw直接放在main中的try/catch块中作为测试,仍然会出现段错误。它从未被允许传播到足以触发任何析构函数的程度。当我读到你的建议时,我几乎做了一个双重反转。我肯定没有想到那个可能性! - Sam Marinelli
2
不客气,我只是向你提出一些想法。我对gcc并不那么熟悉,特别是更奇特的配置。文档肯定会写得像“这里有一堆拼凑着的东西来禁用异常,但请注意风险”。 - Persixty
1个回答

2
正如链接的问题所指出的,GCC需要允许-fno-exceptions和-fexceptions共存,以便链接C和C++。
在更理论的层面上,异常问题与程序的调用图密切相关。这是一个有向图(调用者/被调用者),但它可以是循环的,并且节点之间可以有多条边。现在每个函数/节点都可以编译为带有或不带有异常。我们可以将安全程序定义为从“没有异常”节点无法到达“有异常”节点的程序。
这可能过于严格——一个在try...catch(...) {}块中的C++代码片段应该可以从C代码中调用。但我不知道是否有GCC的保证。并考虑其含义——调用图与调用堆栈有关。调用堆栈通常形成从main()到当前执行函数的路径。如果整个路径都具有异常感知性,则异常是安全的。但是,如果有一个函数不了解异常,它可能会使堆栈处于一种状态,即使堆栈展开不会展开到那么远,也无法安全地处理异常。

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