例如,可以捕获 SIGABRT 并通过 longjump 继续程序。
我想知道当我总是调用调用 abort() 的函数时,这是否会导致堆栈溢出。
我需要知道这一点,因为我想在单元测试中使用断言宏(taht 调用中止)。如果断言失败,我想继续下一个单元测试。
例如,可以捕获 SIGABRT 并通过 longjump 继续程序。
我想知道当我总是调用调用 abort() 的函数时,这是否会导致堆栈溢出。
我需要知道这一点,因为我想在单元测试中使用断言宏(taht 调用中止)。如果断言失败,我想继续下一个单元测试。
abort
不需要清栈;longjmp
将“清除”它,因为它将堆栈指针倒回到setjmp
. 如果其他一切都正确,则重复调用longjmp
并且setjmp
不会导致堆栈溢出。
但是,longjmp
将跳过正常的执行路径,它可以自己调用资源泄漏。考虑这段代码:
char *s = malloc(...);
... use s ...
free(s);
如果“... use s ...”部分调用longjmp
了代码之外的某个函数,free
那么您将没有机会被调用并且您将泄漏。这同样适用于关闭打开的文件、套接字、释放共享内存段、收获分叉的孩子等等。
由于这个原因longjmp
,在 C 编程中很少使用。assert
如果您不是要退出程序,我的建议是避免。只需在单元测试中使用另一个宏,或切换到提供该宏的测试框架。
假设 POSIX,调用longjmp
以退出SIGABRT
引发者abort
是有效的,因为abort
被指定为异步信号安全(也因为此信号不是异步的)。(在纯 C 语言中,从信号处理程序中执行的几乎所有操作都是 UB,因此这通常不是一个有趣的案例。)但是,您有责任确保您自己的程序状态不会因此而不一致,在这样的情况下一种会导致您的程序在程序流中立即或稍后以某种其他方式调用 UB 的方式。
话虽如此,我同意 user4815162342 的观点,即您的提议是一种非常糟糕的错误处理形式。如果您不想中止,请不要调用abort
,而是编写自己的错误处理函数。
longjmp不会展开堆栈,但会修改堆栈指针:
如果调用 setjmp 的函数返回,则不再可能安全地使用 longjmp 和相应的 jmp_buf 对象。这是因为函数返回时堆栈帧无效。调用 longjmp 会恢复堆栈指针,因为返回的函数将指向一个不存在且可能被覆盖/损坏的堆栈帧。