我有一个程序,有时会因指针运算而出现段错误。我知道会发生这种情况,但我无法轻松地提前检查它是否出现段错误 - 我可以“预扫描”输入数据以查看它是否会导致段错误(这可能无法确定),或者我可以重新调整它以不使用指针算术,这将需要大量的工作,或者我可以尝试捕获段错误。所以我的问题是:

1)在C语言中,我如何捕获段错误?我知道 某物 操作系统中的错误会导致段错误,但是如果 C 程序发生段错误,它能做些什么来比仅仅更优雅地死掉呢? Segmentation fault?

2)这有多便携?

我认为这是一种非常不可移植的行为,因此如果您发布任何代码来捕获段错误,请告诉我它的作用。我使用的是 Mac OS X,但我希望我的程序能够在尽可能多的平台上运行,并且我想看看我的选择是什么。

别担心 - 基本上我想做的就是打印一条更用户友好的错误消息并释放一些 malloc()ed记忆,然后死掉。我不打算忽略我遇到的所有段错误并继续前进。

有帮助吗?

解决方案

您必须定义一个信号处理程序。这是使用功能,在Unix系统上做 sigaction 。我做这个用在Fedora上相同的代码64位和32位,并在Sun Solaris。

其他提示

那么,SIGSEGV是可捕获的,并且这是POSIX,所以在这个意义上可移植的。

卜我担心你似乎要处理的段错误,而不是解决引起的段错误的问题。如果我不得不选择它是否是操作系统的错,还是我自己的代码,我知道我会选择。我建议你追捕这个bug,修复它,然后写一个测试案例,以确保它不会再咬你。

您可以使用该功能的信号的安装了信号的新信号处理程序:

   #include <signal.h>
   void (*signal(int signum, void (*sighandler)(int)))(int);

类似下面的代码:

signal(SIGINT , clean_exit_on_sig);
signal(SIGABRT , clean_exit_on_sig);
signal(SIGILL , clean_exit_on_sig);
signal(SIGFPE , clean_exit_on_sig);
signal(SIGSEGV, clean_exit_on_sig); // <-- this one is for segmentation fault
signal(SIGTERM , clean_exit_on_sig);

void 
clean_exit_on_sig(int sig_num)
{
        printf ("\n Signal %d received",sig_num);
}

在信号处理程序中的安全操作是的非常限制。这是不安全的任何调用库函数不知道是重入,这将排除,例如,free()printf()。最佳做法是设定一个变数回报,但这并不能帮助你了。这也是安全的使用系统调用,如write()

请注意,在这里给出的两个回溯例子中,backtrace_symbols_fd()功能将是安全的,因为它使用的原料直接FD,但调用fprintf()是不正确的,应该通过一种用途write()来代替。

我认为你正在试图解决一个不存在的问题。至少你的工作方向是错误的。你将无法 抓住 分段错误,因为此错误/异常是由操作系统引发的(它是 造成的 通过你的程序,操作系统只是 捕获物 它)。

我建议您重新考虑有关输入的策略:为什么无法消毒?最重要的是大小检查,为此 C stdlib 具有适当的函数。当然,您必须检查有关内容的有效输入。是的,这可能会导致大量工作,但这是编写健壮程序的唯一方法。

编辑: 我不是一个 C 专家,不知道即使是分段错误也可以由信号处理程序处理。不过,由于上述原因,我认为这不是正确的方法。

您需要提供一个SIGSEGV处理程序,这个看起来相当不错。

信号处理(相对)可以跨 UNIX 机器(包括 Mac 和 Linux)移植。最大的区别在于异常详细信息,它作为参数传递给信号处理例程。抱歉,但是如果您想打印更合理的错误消息(例如故障发生的位置和原因),您可能需要一堆 #ifdef ......

好的,这里有一个代码片段供您开始:

#include <signal.h>

/* reached when a segv occurrs */
void
SEGVFunction( SIGARGS )
{
     ...
}

...
main(...) {
    signal(SIGSEGV, SEGVFunction); /* tell the OS, where to go in case... */
    ...
    ... do your work ...
}

你的任务是:

  • 检查 SIGARGS 是什么(取决于操作系统,因此使用 ifdef)
  • 查看如何从sigArgs中的异常信息中提取fault-address和pc
  • 打印合理的消息
  • 出口

理论上,您甚至可以在信号处理程序中修补电脑(在错误指令之后),然后继续。然而,典型的信号处理程序要么 exit() 要么将 longjmp() 返回到 main 中的保存位置。

问候

有一个如何赶上SIGSEGV和使用的glibc的回溯(打印堆栈跟踪的示例)这里:

如何当产生堆栈跟踪我C ++的应用程序崩溃

您可以用它来抓住你的段错误和清理,但被警告:你不应该在信号处理程序做了太多的东西,特别的东西,包括拨打电话一样的malloc()。有很多未信号安全的电话,你可以最终搬起石头砸自己的脚,如果你做,比如说,一个电话将通过malloc内的malloc。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top