【问题标题】:Program freezes while catching signal程序在捕获信号时冻结
【发布时间】: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 函数是安全的。但是当它冻结时,我不知道没有它我该怎么做。

标签: c linux windows signals


【解决方案1】:

按照@Shawn 和@None 的建议,我发现解决方案是避免使用backtrace_symbols 函数。 backtrace_symbols_fd 更好,因为它不使用 malloc。 更好的事情有时是最简单的。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-13
  • 2015-03-24
  • 2011-01-26
  • 1970-01-01
  • 2013-12-16
  • 1970-01-01
  • 2018-01-24
相关资源
最近更新 更多