简体   繁体   English

C中的abort()函数是否清理堆栈?

[英]Does the abort() function in C clean the stack?

It's possible to catch the SIGABRT and continue the program with a longjump for example. 例如,有可能赶上SIGABRT并继续执行该程序,只需进行一次长跳。

I wonder if this can lead to a stack overflow when I always call functions that invoke abort(). 我一直在调用调用abort()的函数时,不知道是否会导致堆栈溢出。

I need to know that because i want to use the assert macro (taht calls abort) in unit tests. 我需要知道,因为我想在单元测试中使用assert宏(taht调用中止)。 If an assert fails, I want to continue with the next unit test. 如果断言失败,我想继续进行下一个单元测试。

abort doesn't need to clear the stack; abort不需要清除堆栈; longjmp will "clear" it in that it will rewind the stack pointer back to the position of setjmp . longjmp会“清除”它,因为它将堆栈指针退回到setjmp的位置。 If all else is correct, repeatedly invoking longjmp and setjmp will not cause stack overflow. 如果其他所有方法都正确,则反复调用longjmpsetjmp不会导致堆栈溢出。

However, longjmp will skip normal execution path, which can call resource leaks in its own right. 但是, longjmp将跳过正常的执行路径,这可能会自行调用资源泄漏。 Consider this code: 考虑以下代码:

char *s = malloc(...);
... use s ...
free(s);

If the "... use s ..." portion calls some function that longjmp s out of the code, free won't get a chance to get called and you will leak. 如果“ ... use s ...”部分从代码中调用了longjmp s的某些函数,则free不会有被调用的机会,并且您会泄漏。 The same applies to closing open files, sockets, freeing shared memory segments, reaping forked children, and so on. 这同样适用于关闭打开的文件,套接字,释放共享内存段,获取分叉的子对象等。

For this reason longjmp is rarely used in C programming. 因此, longjmp很少在C编程中使用。 My advice would be to avoid assert if you don't mean the program to exit. 我的建议是,如果您不打算退出程序,请避免assert Simply use another macro in your unit tests, or switch to a testing framework that provides one. 只需在单元测试中使用另一个宏,或切换到提供该宏的测试框架即可。

longjmp does not unwind the stack, but it does modify the stack pointer: longjmp不会展开堆栈,但是会修改堆栈指针:

If the function in which setjmp was called returns, it is no longer possible to safely use longjmp with the corresponding jmp_buf object. 如果返回了调用setjmp的函数,则不再可以安全地将longjmp与相应的jmp_buf对象一起使用。 This is because the stack frame is invalidated when the function returns. 这是因为函数返回时,堆栈帧无效。 Calling longjmp restores the stack pointer , which—because the function returned—would point to a non-existent and potentially overwritten/corrupted stack frame. 调用longjmp将恢复堆栈指针 ,由于返回了函数,该指针将指向不存在的,可能会被覆盖/损坏的堆栈帧。

Assuming POSIX, calling longjmp to get out of the SIGABRT raised by abort is valid, because abort is specified to be async-signal-safe (and also because this signal is not asynchronous). 假定为POSIX,则调用longjmp来退出abort引发的SIGABRT是有效的,因为abort被指定为异步信号安全的(并且还因为该信号不是异步的)。 (In plain C, doing almost anything from a signal handler is UB so it's usually not an interesting case to talk about.) However, it's your responsibility to make sure that none of your own program's state is left inconsistent as a result, in such a way that it would cause your program to invoke UB in some other way immediately or much later in the program flow. (在普通C语言中,从信号处理程序执行几乎所有操作都是UB,因此通常不应该谈论这个有趣的情况。)但是,您有责任确保自己程序的状态不会因此而保持不一致,在这种情况下一种使您的程序立即或在程序流程中更晚时间以其他方式调用UB的方式。

With that said, I agree with user4815162342 that your proposal is a very bad form of error handling. 话虽如此,我同意user4815162342的建议,这是错误处理的一种非常糟糕的形式。 If you don't want to abort, don't call abort , but instead write your own error handling functions. 如果您不想中止,请不要调用abort ,而要编写自己的错误处理函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM