1

我想做一些assertaborting 更有用的事情,包括刷新一些打开的文件和打印堆栈跟踪。

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

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

4

1 回答 1

2

assert()用你自己的实现劫持怎么样?在 Unix 系统上,您可以使用LD_PRELOAD 技巧来劫持__assert_failassert()它本身只是一个调用后者的宏)。

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

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

  2. 如果您决定捕获 SIGABRT,您应该记住,信号处理程序“合法”不允许做很多事情(甚至不能调用 printf),这使它们成为您要求做“更有用的事情”的不好候选人。

    因此,最好有一个专用线程永久等待信号sigwait()(基于如何abort()实现,这可能不是一个选项),或者在收到信号时由信号处理程序通知它可以完成大部分工作在信号处理程序上下文之外。

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

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

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

如果SIGABRT信号被忽略,或者被返回的处理程序捕获,abort()函数仍将终止进程。它通过恢复SIGABRT的默认配置然后再次提高信号来实现这一点。

于 2013-02-14T07:41:45.197 回答