分段错误处理
- 2024-10-12 10:28:00
- admin 原创
- 105
问题描述:
我有一个应用程序,用于捕获任何分段错误或 ctrl-c。使用下面的代码,我能够捕获分段错误,但处理程序被一次又一次地调用。我该如何阻止它们。供您参考,我不想退出我的应用程序。我只需要小心地释放所有损坏的缓冲区。
是否可以?
void SignalInit(void )
{
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = mysighandler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
sigaction(SIGSEGV, &sigIntHandler, NULL);
}
处理程序如下。
void mysighandler()
{
MyfreeBuffers(); /*related to my applciation*/
}
这里对于分段错误信号,处理程序被多次调用,并且显然 MyfreeBuffers() 会给出释放已释放内存的错误。我只想释放一次,但仍然不想退出应用程序。
请帮忙。
解决方案 1:
此类事件的默认操作SIGSEGV
是终止您的进程,但由于您已为其安装了处理程序,因此它将调用您的处理程序来覆盖默认行为。但问题是,在处理程序完成后,可能会重试分段错误指令,如果您未采取措施修复第一个分段错误,则重试的指令将再次出错,并不断重复。
因此,首先找出导致该问题的指令SIGSEGV
并尝试修复它(您可以backtrace()
在处理程序中调用类似的指令并亲自查看出了什么问题)
此外,POSIX 标准还规定,
当进程从信号捕获函数正常返回 [XSI] SIGBUS、SIGFPE、SIGILL 或 SIGSEGV 信号(该信号不是由 kill()、[RTS] sigqueue() 或 raise() 生成的)后,其行为是未定义的。
因此,最理想的做法是首先修复段错误。段错误处理程序并非旨在绕过底层错误情况
因此,最好的建议是 -不要捕获SIGSEGV
。让它转储核心。分析核心。修复无效的内存引用,然后就可以了!
解决方案 2:
我完全不同意“不要捕捉 SIGSEGV”的说法。
这是处理意外情况的非常好的做法。使用与 相关的信号机制来处理NULL指针(由 malloc 失败提供)setjmp/longjmp
比在整个代码中分配错误情况管理要干净得多。
但请注意,如果您在上使用“sigaction” SEGV
,则一定不要忘记说SA_NODEFER
-sa_flags
或者找到另一种方法来处理SEGV
只会触发处理程序一次的事实。
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
static void do_segv()
{
int *segv;
segv = 0; /* malloc(a_huge_amount); */
*segv = 1;
}
sigjmp_buf point;
static void handler(int sig, siginfo_t *dont_care, void *dont_care_either)
{
longjmp(point, 1);
}
int main()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sigaction));
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NODEFER;
sa.sa_sigaction = handler;
sigaction(SIGSEGV, &sa, NULL); /* ignore whether it works or not */
if (setjmp(point) == 0)
do_segv();
else
fprintf(stderr, "rather unexpected error
");
return 0;
}
解决方案 3:
如果SIGSEGV
再次触发,那么显而易见的结论是,对的调用MyfreeBuffers();
并没有解决根本问题(如果该函数确实只free()
分配了一些内存,我不确定你为什么会认为它会这样做)。
大致来说,SIGSEGV
当尝试访问无法访问的内存地址时会触发。如果您不打算退出应用程序,则需要使该内存地址可访问,或者使用 更改执行路径longjmp()
。
解决方案 4:
您不应该在 之后尝试继续SIG_SEGV
。这基本上意味着您的应用程序的环境在某种程度上被破坏了。可能是您刚刚取消引用了一个空指针,也可能是某个错误导致您的程序破坏了其堆栈、堆或某个指针变量,您只是不知道。唯一安全的做法是终止程序。
处理 control-C 是完全合法的。许多应用程序都这样做,但您必须非常小心在信号处理程序中执行的操作。您不能调用任何不可重入的函数。这意味着如果您MyFreeBuffers()
调用 stdlib函数,您可能会陷入困境。如果用户在程序处于或free()
中间时按下 control-C ,从而在操纵用于跟踪堆分配的数据结构的过程中途按下 或,则如果您在信号处理程序中调用或,则几乎肯定会破坏堆。malloc()
`free()malloc()
free()`
在信号处理程序中,唯一可以安全执行的操作就是设置一个标志,表示您捕获了信号。然后,您的应用可以定期轮询该标志,以决定是否需要执行某些操作。
解决方案 5:
好吧,您可以设置一个状态变量,并且只有在未设置时才释放内存。每次都会调用信号处理程序,据我所知您无法控制这一点。
解决方案 6:
我可以看到从 SIG_SEGV 中恢复的情况,如果您在循环中处理事件,并且其中一个事件导致分段违规,那么您只想跳过此事件,继续处理其余事件。在我看来,SIG_SEGV 类似于 Java 中的 NullPointerException。是的,在这两种情况之后,状态将不一致且未知,但是在某些情况下,您希望处理这种情况并继续。例如,在 Algo 交易中,您可以暂停订单的执行并允许交易者手动接管,而不会导致整个系统崩溃并破坏所有其他订单。
解决方案 7:
看起来至少在 Linux 下使用 -fnon-call-exceptions 选项的技巧可以解决问题。它将能够将信号转换为一般的 C++ 异常并以一般方式处理它。例如,查看linux3/gcc46:“-fnon-call-exceptions”,哪些信号是捕获指令?
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件