捕获 C 中的段错误

发布于 2024-07-13 08:01:24 字数 489 浏览 6 评论 0原文

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

1)在C语言中,我如何捕获段错误? 我知道操作系统中的某些会导致段错误,但是如果 C 程序出现段错误,那么它能做什么,比仅仅段错误更优雅地结束呢?

2)这有多便携?

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

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

I have a program that segfaults from pointer arithmetic sometimes. I know this happens, but I can't easily check ahead of time to see whether it segfaults or not - either I can "pre-scan" input data to see if it will cause a segfault (which can be impossible to determine), or I can refit it to not use pointer arithmetic, which would require a significantly larger amount of work, or I can try to catch a segfault. So my question:

1) How, in C, can I catch a segfault? I know something in the OS causes a segfault, but what can a C program do in the event that it segfaults to die a bit more gracefully than just Segmentation fault?

2) How portable is this?

I imagine this is a highly unportable behavior, so if you post any code to catch a segfault, please tell me what it works on. I'm on Mac OS X but I'd like my program to work on as many platforms as it can and I want to see what my options are.

And don't worry - basically all I want to do is print a more user-friendly error message and free some malloc()ed memory, and then die. I'm not planning on just ignoring all segfaults I get and plowing ahead.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云之铃。 2024-07-20 08:01:24

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

   #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);
}

You can use the function signal to install a new signal handler for the signal:

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

Something like the following code:

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);
}
梦幻的味道 2024-07-20 08:01:24

您必须定义一个信号处理程序。 这是在 Unix 系统上使用函数 sigaction 完成的。 我在 Fedora 64 位和 32 位以及 Sun Solaris 上使用相同的代码完成了此操作。

You have to define a signal handler. This is done on Unix systems using the function sigaction. I've done this with the same code on Fedora 64- and 32-bit, and on Sun Solaris.

微凉 2024-07-20 08:01:24

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

请注意,在此处给出的两个回溯示例中,backtrace_symbols_fd() 函数将是安全的,因为它直接使用原始 fd,但对 fprintf() 的调用是不正确的,并应使用 write() 来代替。

The safe actions in a signal handler are very limited. It's unsafe to call any library function not known to be re-entrant, which will exclude, for example, free() and printf(). Best practice is to set a variable and return, but this doesn't help you very much. It's also safe to use system calls such as write().

Note that in the two backtrace examples given here, the backtrace_symbols_fd() function will be safe because it uses the raw fd directly, but the call to fprintf() is incorrect, and should be replaced by a use of write().

灯下孤影 2024-07-20 08:01:24

信号处理(相对)可以跨 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 中的异常信息中提取故障地址和 pc
  • 理论上打印合理的消息
  • 退出

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

问候

signal handling is (relatively) portable across unix machines (this includes mac and linux). The big differences are in the exception detail, which is passed as argument to the signal handling routine. Sorrty, but you will probably need a bunch of #ifdefs for that, if you want to print more reasonable error messages (such as where and due to which address the fault happened) ...

ok, here is a code fragment for you to start with:

#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 ...
}

Your task is to:

  • check what SIGARGS is (OS dependent, so use an ifdef)
  • see how to extract fault-address and pc from the exception information in sigArgs
  • print reasonable message
  • exit

in theory, you could even patch the pc in the signal handler (to after the faulting instruction), and proceed. However, typical signal handlers either exit() or to a longjmp() back into a save place in the main.

regards

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文