C++ 是否可以从std::abort恢复?

C++ 是否可以从std::abort恢复?,c++,unit-testing,abort,C++,Unit Testing,Abort,我们的C代码库用于检查是否满足先决条件/后决条件 #include <cstdlib> #include <cassert> void Aborting_Function(int n); int main(){ Aborting_Function(1); //good Aborting_Function(0); //calls std::abort() //Is it possible to recover somehow? //A

我们的C代码库用于检查是否满足先决条件/后决条件

#include <cstdlib>
#include <cassert>

void Aborting_Function(int n);

int main(){

    Aborting_Function(1); //good
    Aborting_Function(0); //calls std::abort()

    //Is it possible to recover somehow?
    //And continue on...
}

void Aborting_Function(int n){
    assert(n > 0);
    //impl...
}
#包括
#包括
无效中止_函数(int n);
int main(){
正在中止_函数(1);//良好
正在中止_函数(0);//调用std::abort()
//有可能以某种方式恢复吗?
//继续。。。
}
无效中止_函数(int n){
断言(n>0);
//暗示。。。
}
在单元测试中,我想验证函数是否正确地遵循了它们的约定
(在应该的时候中止)

是否可以从std::abort恢复?

我意识到让单元测试检查与断言应该检查的完全相同的东西似乎有点重复,但这会很有帮助,因为我们可以自动检查不应该工作的特定用例

是否可以从
std::abort
恢复

这取决于你所说的恢复是什么意思。从

导致异常程序终止,除非传递给signal的信号处理程序捕捉到SIGABRT,并且处理程序不返回

如果您希望能够从调用
std::abort
的位置继续,那么答案是No。如果您希望能够在程序退出之前执行某些操作,那么答案是

我猜您希望能够从调用
std::abort
的位置继续。因此,对于您的用例,答案是否定的。

根据POSIX

abort()函数将导致异常进程终止,除非捕获信号SIGABRT且信号处理程序不返回

这意味着,如果捕获到信号并且信号处理程序返回,仍然需要终止程序(例如,将信号处理程序重置为默认终止行为,然后再次提升信号)

因此,“恢复”的唯一方法是捕获信号,而不是从信号处理程序返回。因此,
中止函数(0)
后的行无法到达。此外,您可能不希望您的程序在信号处理程序中度过余生,因为这样所有外部变量都变得不安全,无法访问(无锁原子除外)。不太好

但是在窗户上?我不知道。

简短的回答是“不”

而不是颠覆Apple(),您可能需要考虑使用谷歌测试框架。

这有死亡测试(这里的文档:)


本质上,这是一个叉子进程,并检查语句是否导致它退出(如果它中止了,它会做什么)。

< P>单元测试,可以从那里替换BoeToE()和LangJMP(),或者通过C++从那里进行测试时。 例如(用C++表示):

产生以下输出:

...
assert(false):
Assertion failed: false, file abort-own.cpp, line 45
Intercepted abort
End
使用VC14之前版本的编译器编译会产生链接错误:

LIBCMT.lib(abort.obj) : error LNK2005: _abort already defined in {file}
{exe} : fatal error LNK1169: one or more multiply defined symbols found
这可通过以下方式治愈:

  • 包括在编制时
使用
-std=c++03
-std=c++11
通过g++进行编译不会产生多重定义的符号

我为以下项目开发的上述代码的更详细版本:

  • ,

  • 有一种方法可以做到这一点,但它有点不一致

    您可以使用HippoMocks(免责声明:我是作者)来模拟该函数,并使它抛出一个异常,然后使用该异常在测试框架中进行检查。您不能让它返回值,因为它被标记为noreturn,并且编译器将不会生成任何代码来处理它的返回

    EXPECT_CALL(&abort).Throw(42);
    
    请注意,这违反了C和C++中至少5种不同的规则,所以更大的问题是,你应该吗?据我所知,您使用资产来防止出现内部不一致的情况。这些都是你不应该测试的东西。您的所有程序在有无断言的情况下都应同样有效。如果您希望从您的代码中测试任何类型的行为,那么这永远不应该是断言,因为这不是一个意外的状态(见鬼,您正在测试该状态,所以这是一个经过良好测试的状态)


    所以你可以,但你不应该想。

    不要使用
    assert(x)
    ,而是
    我们的断言(x)
    ,它被有条件地定义为不做任何事情(发布),
    assert(x)
    (调试),做一些有趣的事情(测试)?我没有得到一个要点。对于因输入错误而中止的函数的单元测试,您期望的结果将是中止。有什么问题吗?@DietmarKühl这可能是我们最好的路线。它将依赖于我们更新大部分代码库,但这可能是唯一的方法。根据标准
    abort()
    :程序终止时不会对自动、线程或静态存储持续时间的对象执行析构函数,也不会调用传递给atexit()@SergeyA的函数。我们需要一个测试用例列表,在这里,我们可以确认“是的,这50个单独的函数调用将在给定指定输入的情况下中止。”。然而,当第一个测试用例中止时,似乎没有恢复的方法。您可以使用
    setjmp
    longjmp
    来摆脱中止上下文吗?@Barmar我相信是的,但这并不能解决在信号处理程序之外访问变量的问题。你也只能跳转到你已经去过的地方。我想你应该在调用
    中止函数()之前调用
    setjmp
    ,然后测试
    SIGABRT
    设置的变量。+1用setjmp/longjmp测试,我们有一个测试,表明我们的崩溃处理程序可以处理SEGFULTS,并用它进行检查。当然,您也可以使用SIGABRT处理程序并在那里实现它…@dascandy longjmp来自SIGABRT处理程序,就像从它抛出一样。然而,根据标准,你能从这样的处理者那里做的很少。见肌萎缩侧索硬化
    LIBCMT.lib(abort.obj) : error LNK2005: _abort already defined in {file}
    {exe} : fatal error LNK1169: one or more multiply defined symbols found
    
    EXPECT_CALL(&abort).Throw(42);