Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言中捕捉SegFault_C_Macos_Error Handling_Segmentation Fault - Fatal编程技术网

在C语言中捕捉SegFault

在C语言中捕捉SegFault,c,macos,error-handling,segmentation-fault,C,Macos,Error Handling,Segmentation Fault,我有一个程序,有时会将错误与指针算法区分开来。我知道会发生这种情况,但我无法提前轻松检查它是否存在SEGFULT——要么我可以“预扫描”输入数据,看看它是否会导致SEGFULT(这可能无法确定),要么我可以重新调整它,使其不使用指针算法,这将需要大量的工作,或者我可以尝试捕获SEGFULT。因此,我的问题是: 1) 在C语言中,我怎样才能抓住一个错误?我知道操作系统中的某些东西会导致segfault,但是如果一个C程序的segfault比Segmentation fault更优雅地死去,它能做些

我有一个程序,有时会将错误与指针算法区分开来。我知道会发生这种情况,但我无法提前轻松检查它是否存在SEGFULT——要么我可以“预扫描”输入数据,看看它是否会导致SEGFULT(这可能无法确定),要么我可以重新调整它,使其不使用指针算法,这将需要大量的工作,或者我可以尝试捕获SEGFULT。因此,我的问题是:

1) 在C语言中,我怎样才能抓住一个错误?我知道操作系统中的某些东西会导致segfault,但是如果一个C程序的segfault比Segmentation fault更优雅地死去,它能做些什么呢

2) 这个有多便携

我想这是一种非常不可移植的行为,所以如果您发布任何代码来捕获segfault,请告诉我它的工作原理。我在Mac OS X上,但我希望我的程序能在尽可能多的平台上运行,我想看看我的选项是什么


别担心——基本上,我只想打印一条更加用户友好的错误消息,释放一些
malloc()
ed内存,然后死掉。我不打算忽略我遇到的所有故障,继续前进。

你必须定义一个信号处理器。这是在Unix系统上使用函数完成的。我在Fedora64位和32位以及Sun Solaris上使用了相同的代码

SIGSEGV是可捕获的,这是POSIX,所以从这个意义上说它是可移植的


但我担心的是,您似乎希望处理SEGFULT,而不是修复导致SEGFULT的问题。如果我必须选择是操作系统出了问题,还是我自己的代码出了问题,我知道我会选择哪个。我建议你找出那个bug,修复它,然后编写一个测试用例,确保它不再咬你。

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

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

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

您可以使用函数信号为信号安装新的信号处理程序:

   #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);
}
信号(信号灯上的信号灯、清洁出口信号灯);
信号机(信号机,信号机上的清洁出口);
信号机(信号机上的信号机、清洁出口信号机);
信号(SIGFPE,信号灯上的清洁出口);

信号(SIGSEGV,清洁出口在sig上);// 您需要提供一个SIGSEGV处理程序,

这里有一个示例,说明如何使用glibc的backtrace()捕获SIGSEGV并打印堆栈跟踪:

您可以使用它来捕获segfault并进行清理,但需要注意的是:您不应该在信号处理程序中做太多的事情,尤其是涉及调用malloc()之类的事情。有很多调用都不是信号安全的,如果你从malloc内部调用malloc,你最终可能会自食其果。

信号处理在unix机器上(包括mac和linux)是(相对)可移植的。最大的区别在于异常细节,它作为参数传递给信号处理例程。Sorrty,但是如果您想打印更合理的错误消息(例如故障发生的位置和原因),您可能需要一组#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 ...
}
#包括
/*发生segv时到达*/
无效的
SEGVFunction(SIGARGS)
{
...
}
...
主要(…){
信号(SIGSEGV,SEGVFunction);/*告诉操作系统,万一*/
...
…做你的工作。。。
}
你的任务是:

  • 检查SIGARGS是什么(依赖于操作系统,因此请使用ifdef)
  • 请参见如何从sigArgs中的异常信息中提取故障地址和pc
  • 打印合理的消息
  • 出口
理论上,您甚至可以在信号处理程序中修补pc(在错误指令之后),然后继续。但是,典型的信号处理程序要么退出(),要么将longjmp()返回到main中的保存位置


关于

信号处理器中的安全操作是非常有限的。调用任何不知道是可重入的库函数是不安全的,例如,它将排除
free()
printf()
。最佳实践是设置一个变量并返回,但这对您帮助不大。使用系统调用(如
write()
)也是安全的


请注意,在这里给出的两个回溯示例中,
backtrace\u symbols\u fd()
函数将是安全的,因为它直接使用原始fd,但是对
fprintf()
的调用是不正确的,应该使用
write()

来代替,默认模式是安全的,可以保护用户不耗尽内存(它使用链接列表)。他们必须明确选择使用“不太安全”的版本,并且应该意识到这样做的后果。提供“不太安全”的版本是为了与其他程序兼容,这些程序不像我的程序那样提供无限链接列表。另外,如果没有其他问题,我会学到一些新东西。我想他的意思是“某物”在操作系统中捕获了违规行为,而不是操作系统是故障的原因。大小检查不是问题——用户输入一个程序(在brainf*ck中),我的程序运行它。检查有效的输入运行