Pergunta

Se por algum milagre um segfault ocorre em nosso programa, eu quero pegar o SIGSEGV e permitir que o usuário (possivelmente um cliente GUI) sabe com um único código de retorno que um problema grave ocorreu. Ao mesmo tempo, eu gostaria de exibir informações sobre a linha de comando para mostrar que o sinal foi capturado.

Hoje o nosso sinal do manipulador é o seguinte:

void catchSignal (int reason) {
  std :: cerr << "Caught a signal: " << reason << std::endl;
  exit (1);
}

Eu posso ouvir os gritos de horror com o anterior, como eu li a partir desta fio que é mal para chamar uma função não reentrante de um manipulador de sinal.

Existe uma maneira portátil para lidar com o sinal e fornecer informações aos usuários?

EDIT:? Ou pelo menos portátil no âmbito POSIX

Foi útil?

Solução

Esta tabela lista todas as funções que garantias POSIX para ser-sinal assíncrono-safe e por isso pode ser chamado de um manipulador de sinal.

Ao usar o comando 'escrever' a partir desta tabela, o seguinte relativamente solução "feio" espero que irá fazer o truque:

#include <csignal>

#ifdef _WINDOWS_
#define _exit _Exit
#else
#include <unistd.h>
#endif

#define PRINT_SIGNAL(X) case X: \
          write (STDERR_FILENO, #X ")\n" , sizeof(#X ")\n")-1); \
          break;

void catchSignal (int reason) {
  char s[] = "Caught signal: (";
  write (STDERR_FILENO, s, sizeof(s) - 1);
  switch (reason)
  {
    // These are the handlers that we catch
    PRINT_SIGNAL(SIGUSR1);
    PRINT_SIGNAL(SIGHUP);
    PRINT_SIGNAL(SIGINT);
    PRINT_SIGNAL(SIGQUIT);
    PRINT_SIGNAL(SIGABRT);
    PRINT_SIGNAL(SIGILL);
    PRINT_SIGNAL(SIGFPE);
    PRINT_SIGNAL(SIGBUS);
    PRINT_SIGNAL(SIGSEGV);
    PRINT_SIGNAL(SIGTERM);
  }

  _Exit (1);  // 'exit' is not async-signal-safe
}

EDIT:. Com base janelas

Depois de tentar construir este janelas, parece que 'STDERR_FILENO' não está definido. A partir da documentação no entanto seu valor parece ser '2'.

#include <io.h>
#define STDIO_FILENO 2

EDIT: 'saída' não deve ser chamado a partir do manipulador de sinal seja

Como apontado por fizzer , chamando _exit no exemplo acima é uma abordagem marreta para sinais tais como HUP e TERMO. Idealmente, quando estes sinais são apanhados uma bandeira com o tipo "sig_atomic_t volátil" pode ser usado para notificar o programa principal que ele deve sair.

A seguir, eu achei útil em minhas pesquisas.

  1. Sinais Introdução ao Unix programação
  2. Estendendo Sinais tradicionais

Outras dicas

FWIW, 2 é o erro padrão no Windows também, mas você vai precisar de algum compilação condicional porque seu write () é chamado _write (). Você também vai querer

#ifdef SIGUSR1 /* or whatever */

etc em torno de todas as referências a sinais não garantidos para ser definida pelo padrão C.

Além disso, como mencionado acima, você não quer lidar com SIGUSR1, SIGHUP, SIGINT, SIGQUIT e SIGTERM assim.

Richard, ainda não é suficiente karma ao comentário, por isso, uma nova resposta que eu tenho medo. Estes sinais são assíncronas; você não tem idéia quando eles são entregues, por isso, eventualmente, você vai estar no código da biblioteca que precisa para completar para ficar consistente. manipuladores de sinais para estes sinais são, portanto, necessários para retorno. Se você chamar exit (), a biblioteca vai fazer algum trabalho de pós-main (), incluindo chamar funções registradas com atexit () e limpar os fluxos padrão. Este processamento pode falhar se, por exemplo, o sinal chegou em uma função de I / O biblioteca padrão. Portanto, em C90 você não tem permissão para chamar exit (). Vejo agora C99 relaxa a exigência, fornecendo um novo _exit function () em stdlib.h. _Exit () pode seguramente ser chamado de um manipulador para um sinal assíncrono. _Exit () não vai chamar atexit () funções e pode omitir limpar os fluxos padrão a critério da implementação.

Para bk1e (comentarista alguns posts acima) O fato de que SIGSEGV é síncrono é por isso que você não pode usar funções que não são projetados para ser reentrante. E se a função que caiu estava segurando um bloqueio, e a função chamada pelas tentativas manipulador de sinal para adquirir o mesmo bloqueio?

Esta é uma possibilidade, mas não é 'o facto de SIGSEGV é síncrona', que é o problema. Chamando funções não-reentrantes do manipulador é muito pior com sinais assíncronos por dois motivos:

  • manipuladores de sinais assíncronos são (Em geral) esperando para voltar e retomar a execução normal do programa. UMA manipulador para um sinal síncrono é (Geralmente) vai terminar de qualquer maneira, para que você não tenha perdido muito se você deixa de funcionar.
  • em um sentido perverso, você tem controle absoluto sobre quando um sinal síncrono é entregue - acontece como você executar o seu código defeituoso, e em nenhum outro momento. Você não tem controle algum sobre quando um sinal assíncrono é entregue. A menos próprio código de I / O do OP é ifself a causa do defeito - por exemplo, a saída de uma má char * -. a mensagem de erro tem uma chance razoável de sucesso

Escreva um programa lançador para executar o programa e informar o código de saída anormal para o usuário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top