【发布时间】:2020-11-08 16:13:54
【问题描述】:
我试图在我的程序中捕获信号以显示回溯。它多次运行良好,但对于某些信号,它会冻结。 我的代码:
static void signal_handled(int s) {
#ifdef _OPENMP
#pragma omp single
#endif
{
g_printf("Error, signal %d:\n", s);
const gchar *visit = _("Please report this bug to: " PACKAGE_BUGREPORT);
switch (s) {
case SIGSEGV:
case SIGFPE:
case SIGABRT:
case SIGILL:
g_printf(ANSI_COLOR_RED"%s\n"ANSI_COLOR_RESET, visit);
}
#if (!defined _WIN32 && defined HAVE_EXECINFO_H)
int i;
void *stack[STACK_DEPTH];
size_t size = backtrace(stack, sizeof(stack) / sizeof(void*));
char **message = backtrace_symbols(stack, size);
if (message != NULL && message[0] != NULL) {
for (i = 0; i < size && message != NULL; ++i) {
g_printf("[#%i] in %s\n", i, message[i]);
}
free(message);
}
#else
unsigned int i;
void *stack[STACK_DEPTH];
unsigned short size;
SYMBOL_INFO *symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
size = CaptureStackBackTrace(0, sizeof(stack) / sizeof(void*), stack, NULL);
symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
for (i = 0; i < size; i++) {
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
g_printf("[#%i]: in %s\n", i, symbol->Name);
}
free(symbol);
#endif
}
undo_flush();
exit(EXIT_FAILURE);
}
void signals_init() {
#ifndef _WIN32
signal(SIGHUP, signal_handled);
signal(SIGQUIT, signal_handled);
signal(SIGBUS, signal_handled);
signal(SIGINT, signal_handled);
signal(SIGTRAP, signal_handled);
#endif
signal(SIGABRT, signal_handled);
signal(SIGFPE, signal_handled);
signal(SIGSEGV, signal_handled);
signal(SIGTERM, signal_handled);
signal(SIGILL, signal_handled);
}
程序在第一次内存分配时冻结。所以在这里,它将冻结在char **message = backtrace_symbols(stack, size); 上,因此不会显示回溯,用户等待永远不会发生的程序结束。
同样,它不依赖于信号。有些信号 11 可以,有些则不行。 6 也一样,依此类推...
有没有一种安全的方式来显示回溯?为什么程序在显示之前就冻结了?
【问题讨论】:
-
您的信号处理程序肯定调用了一些非信号处理程序安全函数,我敢打赌大多数非标准函数也是不安全的......
-
好的,但我认为至少 SIGSEGV 是标准的?因为我什至有它的问题。不过我会读你的页面。
-
@lock:不,Shawn 的意思是信号处理程序是一种特殊类型的函数,其中只有某些函数可以安全使用。这些函数被称为 async-signal safe,并在上述函数中列出。你使用例如
g_printf()、malloc()、free(),它们都不是异步信号安全的,可能是它冻结的原因。 (请注意,信号处理程序上下文很复杂,因此即使您“测试”某些函数在某些情况下有效,并不意味着它们在所有情况下都有效。您在这里只能信任异步信号安全函数。) -
哦,谢谢@None!我得到了它。一个问题,我希望 backtrace_symbols 函数是安全的。但是当它冻结时,我不知道没有它我该怎么做。