macos 在 C 中捕获段错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/554138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Catching segfaults in C
提问by Chris Lutz
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 somethingin 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
?
1) 在 C 中,我怎样才能发现段错误?我知道操作系统中的某些东西会导致段错误,但是如果 C 程序出现段错误而死得更优雅一点,那么 C 程序能做Segmentation fault
什么呢?
2) How portable is this?
2)这有多便携?
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.
我想这是一种非常不可移植的行为,所以如果您发布任何代码来捕获段错误,请告诉我它的作用。我在 Mac OS X 上,但我希望我的程序能够在尽可能多的平台上运行,我想看看我的选择是什么。
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.
别担心 - 基本上我想要做的就是打印一个更用户友好的错误消息并释放一些malloc()
ed 内存,然后就死了。我不打算只是忽略我得到的所有段错误并继续前进。
采纳答案by Scottie T
回答by Paul Beckingham
Well, SIGSEGV is trappable, and this is POSIX, so it is portable in that sense.
嗯,SIGSEGV 是可捕获的,这是 POSIX,所以从这个意义上说它是可移植的。
Bu I'm concerned that you seem to want to handle the segfault rather than fix the problem that causes the segfault. If I had to pick whether it was the OS at fault, or my own code, I know which I would choose. I suggest you hunt down that bug, fix it, then write a test case to make sure it never bites you again.
但是我担心您似乎想要处理段错误而不是修复导致段错误的问题。如果我不得不选择是操作系统有问题,还是我自己的代码有问题,我知道我会选择哪个。我建议你找到那个错误,修复它,然后编写一个测试用例以确保它不会再咬你。
回答by Igor Oks
You can use the function signalto install a new signal handler for the signal:
您可以使用函数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);
}
回答by Dale Hagglund
The safe actions in a signal handler are verylimited. 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()
.
信号处理程序中的安全操作非常有限。调用任何未知的可重入库函数是不安全的,例如,这将排除free()
和printf()
。最佳实践是设置一个变量并返回,但这对您没有多大帮助。使用诸如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()
.
请注意,这里给出的两个回溯示例中,该backtrace_symbols_fd()
函数将是安全的,因为它直接使用原始 fd,但对 的调用fprintf()
不正确,应替换为使用write()
.
回答by paprika
I think you are trying to solve a problem that doesn't exist. At least you are working on the wrong end. You won't be able to catcha segmentation fault, as this error/exception is thrown by the OS (it is causedby your program, the OS just catchesit).
我认为您正在尝试解决一个不存在的问题。至少你的工作方向是错误的。您将无法捕获分段错误,因为此错误/异常是由操作系统引发的(它是由您的程序引起的,操作系统只是捕获它)。
I'd advise you to rethink your strategy regarding the input: Why is it impossible to sanitize it? The most important to do is size checking, for this the C stdlib has appropriate functions. Then of course you'd have to check for valid input regarding the content. Yes, this will probably result in a lot of work, but it's the only way to write a robust program.
我建议您重新考虑有关输入的策略:为什么无法对其进行消毒?最重要的是大小检查,为此 C stdlib 具有适当的功能。当然,您必须检查有关内容的有效输入。是的,这可能会导致大量工作,但这是编写健壮程序的唯一方法。
EDIT:I'm not much of a C expert, didn't know that even a segmentation fault could be handled by a signal handler. Still, I think it's not the right way to go for the reasons mentioned above.
编辑:我不是 C 专家,不知道即使是分段错误也可以由信号处理程序处理。尽管如此,由于上述原因,我认为这不是正确的方法。
回答by arul
You'll need to provide a SIGSEGV handler, this one looks quite decent.
你需要提供一个 SIGSEGV 处理程序,这个看起来很不错。
回答by Todd Gamblin
There's an example of how to catch SIGSEGV and print a stack trace using glibc's backtrace() here:
这里有一个示例,说明如何使用 glibc 的 backtrace() 捕获 SIGSEGV 并打印堆栈跟踪:
how to generate a stacktrace when my C++ app crashes
You can use this to catch your segfault and clean up, but be warned: you should not be doing too much stuff in a signal handler, especially things that involve making calls like malloc(). There are a lot of calls that aren't signal safe, and you can end up shooting yourself in the foot if you make, say, a call to malloc from within malloc.
您可以使用它来捕获段错误并进行清理,但要注意:您不应该在信号处理程序中做太多事情,尤其是涉及调用 malloc() 之类的事情。有很多调用不是信号安全的,如果您从 malloc 内部调用 malloc,最终可能会中伤自己。
回答by blabla999
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) ...
信号处理(相对)可跨 unix 机器(包括 mac 和 linux)移植。最大的区别在于异常细节,它作为参数传递给信号处理例程。抱歉,但是如果您想打印更合理的错误消息(例如发生故障的地址和地址),您可能需要一堆#ifdefs...
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
- 检查 SIGARGS 是什么(取决于操作系统,所以使用 ifdef)
- 查看如何从sigArgs中的异常信息中提取fault-address和pc
- 打印合理的消息
- 出口
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.
理论上,您甚至可以在信号处理程序中修补 pc(在错误指令之后),然后继续。但是,典型的信号处理程序要么 exit() 要么将 longjmp() 返回到 main 中的保存位置。
regards
问候