如何使用assert做一些有用的事情?

时间:2013-02-14 05:50:20

标签: c++ signals assert abort

我希望使用assert做一些比abort更有用的事情,包括刷新一些打开的文件,以及打印堆栈跟踪。

我读了几篇关于断言的文章,例如Assertions by Andrei Alexandrescu,其中讨论了如何实现断言。但是,我希望替换我自己的断言处理程序,即使在我的程序使用的第三方库中也是如此。我理解大多数(但不是全部)编译器(gcc,MSVC,clang)&我使用的库(Qt,boost)具有设置用户定义的断言处理程序的选项。但是目前我对assert的Abort,Retry,Ignore功能不感兴趣,所以不要在编译器/库特定的断言处理程序中查找我的代码。

根据我的理解,assert调用发送abort信号的SIGABRT,我可以捕获此信号并执行有用的任务吗?

1 个答案:

答案 0 :(得分:2)

如何使用您自己的实现劫持assert()?在Unix系统上,您可以使用LD_PRELOAD trick来劫持__assert_failassert()本身只是一个调用后者的宏。)

另一种可能性是按照你的建议捕获SIGABRT。但是我看到了一些要求:

  1. 区分对assert()的呼叫与接收SIGABRT的其他可能原因的方法。这可能是来自另一个线程或进程的调用kill(),甚至是对来自abort()本身的堆管理函数(free()malloc()的完整性检查的调用。 )。这可以通过ABRT信号处理程序来完成,方法是检查进程的执行堆栈或在某些系统中传递给sigaction()的上下文(void *参数,无人知道如何使用)。

  2. 如果你决定捕获SIGABRT,你应该记住signal handlers are not "legally" allowed to do much(甚至不是一个电话printf),这使得他们不像你要求的那样做“更有用”的候选人。

    所以最好让专用线程永久性地发挥作用 对于sigwait()的信号(基于abort()的方式) 实施这可能不是一个选项)或信号通知 处理器每当收到一个信号,它就可以完成大部分工作 信号处理程序上下文中的工作。

    此外,重要的是要注意,如果在其实现中,SIGABRT由abort()专门发送到其调用线程,那么它的接收将是同步的,您可以自由地调用异步不安全的函数。

  3. 通过自己捕获信号并修改线程的信号掩码,可能会影响你提到的那些第三方库的信号行为(他们可能自己捕获SIGABRT)。

  4. 即使您使用自己的信号处理程序捕获SIGABRT,您也无法恢复正常执行,因此从abort()调用发送信号,因为(引自alarm(8)):

  5.   

    如果 SIGABRT 信号被忽略,或被返回的处理程序捕获,    abort()函数仍将终止该进程。确实如此          这可以通过恢复 SIGABRT 的默认处置,然后再次提升信号。