Quando um processo recebe o SIGABRT (sinal 6)?

202

Quais são os cenários em que um processo obtém um SIGABRT em C ++? Esse sinal sempre vem de dentro do processo ou pode ser enviado de um processo para outro?

Existe uma maneira de identificar qual processo está enviando esse sinal?

Shree
fonte
3
Existem algumas maneiras. A maneira mais fácil, se você escreveu o programa, é registrar um manipulador de sinal para o SIGABRT que imprima essas informações e libere seus fluxos antes de retornar. A segunda maneira mais fácil é executar o programa dentro do strace. A terceira maneira mais fácil é garantir que o programa gere um arquivo principal quando ele falhar e descobrir através do dump principal.
Parthian Shot

Respostas:

195

abort()envia o processo de chamada ao SIGABRTsinal, é assim que abort()basicamente funciona.

abort()é geralmente chamado por funções de biblioteca que detectam um erro interno ou alguma restrição seriamente quebrada. Por exemplo malloc(), chamará abort()se suas estruturas internas forem danificadas por um estouro de heap.

Mainframe nórdico
fonte
27
para mim, na maioria dos casos, o SIGABRT foi enviado ao libctentar chamar free()um ponteiro não inicializado / corrompido
grandrew
Se eu tiver algum lugar no código, chamada de função virtual pura enterrada de dentro do construtor, isso também pode acabar com o sinal SIGABRT? Estou perguntando quando vejo um erro informando que tenho uma chamada virtual pura, e a próxima linha me dá uma mensagem SIGABRT e o aplicativo trava ou é fechado pelo sistema operacional. Obrigado.
precisa
2
No MacOS, obtivemos o SIGABRT para abrir cerca de 1000 identificadores de arquivos sem fechá-los. Em vez de zombar, nossos testes abstraíram o arquivo com um tipo de leitor mais genérico, que não possui Close()método, por isso foi esquecido. Teve uma grande cobertura embora. : rolleyes:
Zyl
52

SIGABRTé comumente usado pelo libc e outras bibliotecas para abortar o programa em caso de erros críticos. Por exemplo, o glibc envia um SIGABRTno caso de uma corrupção de heap dupla detectada ou outras detectadas.

Além disso, a maioria das assertimplementações é utilizada SIGABRTem caso de falha na declaração.

Além disso, SIGABRTpode ser enviado de qualquer outro processo, como qualquer outro sinal. Obviamente, o processo de envio precisa ser executado como o mesmo usuário ou raiz.

IanH
fonte
49

Você pode enviar qualquer sinal para qualquer processo usando a kill(2)interface:

kill -SIGABRT 30823

O 30823 foi um dashprocesso que eu iniciei, para que eu pudesse encontrar facilmente o processo que queria matar.

$ /bin/dash
$ Aborted

A Abortedsaída é, aparentemente, como dashrelata um SIGABRT.

Ele pode ser enviado diretamente para qualquer processo usando kill(2), ou um processo pode enviar o sinal para si via assert(3), abort(3)ou raise(3).

sarnold
fonte
17

Geralmente acontece quando há um problema com a alocação de memória.

Aconteceu comigo quando meu programa estava tentando alocar uma matriz com tamanho negativo.

Mig
fonte
14

Há outra causa simples no caso de c ++.

std::thread::~thread{
    if((joinable ())
        std::terminate ();
}

ou seja, o escopo do segmento terminou, mas você esqueceu de chamar

thread::join();

ou

thread::detach();
Sudip Bhattarai
fonte
7

O GNU libc imprimirá as informações /dev/ttyreferentes a algumas condições fatais antes de serem chamadas abort()(o que é acionado SIGABRT), mas se você estiver executando o programa como um serviço ou não em uma janela real do terminal, essas mensagens poderão se perder, porque não há tty para exibir as mensagens.

Veja meu post sobre o redirecionamento da libc para gravar no stderr em vez de / dev / tty:

Captura de mensagens de erro da libc, redirecionando de / dev / tty

Mark Lakata
fonte
4

Um caso em que o processo obtém o SIGABRT: Hrvoje mencionado sobre um virtual virtual puro chamado de ctor gerando um aborto, recriei um exemplo para isso. Aqui, quando d deve ser construído, ele primeiro chama seu classe de classe Ator e passa o ponteiro para si mesmo. o Ator chama o método virtual puro antes de a tabela ser preenchida com um ponteiro válido, porque d ainda não foi construído.

#include<iostream>
using namespace std;
class A {
public:
 A(A *pa){pa->f();}
 virtual void f()=0;
};
class D : public A {
public:
 D():A(this){}
 virtual void f() {cout<<"D::f\n";}
};
int main(){
 D d;
 A *pa = &d;
 pa->f();
 return 0;
}

compilar: g ++ -o aa aa.cpp

ulimit -c unlimited

executar: ./aa

pure virtual method called
terminate called without an active exception
Aborted (core dumped)

agora vamos ver rapidamente o arquivo principal e validar que SIGABRT foi realmente chamado:

gdb aa core

veja regs:

i r
rdx            0x6      6
rsi            0x69a    1690
rdi            0x69a    1690
rip            0x7feae3170c37

verifique o código:

disas 0x7feae3170c37

mov    $0xea,%eax  = 234  <- this is the kill syscall, sends signal to process
syscall   <-----

http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

234 sys_tgkill pid_t tgid pid_t pid int sig = 6 = SIGABRT

:)

Alexander Kruman
fonte
2

No meu caso, isso ocorreu devido a uma entrada em uma matriz com um índice igual ao comprimento da matriz.

string x[5];

for(int i=1; i<=5; i++){

    cin>>x[i];

}

x [5] está sendo acessado que não está presente.

anônimo
fonte
1

Como "@sarnold", apropriadamente apontado, qualquer processo pode enviar sinal para qualquer outro processo, portanto, um processo pode enviar SIGABORT para outro processo e, nesse caso, o processo de recebimento é incapaz de distinguir se está ocorrendo devido a seus próprios ajustes de memória etc, ou alguém tiver "unicastly", envie para ele.

Em um dos sistemas que trabalhei, há um detector de impasse que realmente detecta se o processo está saindo de alguma tarefa dando batimentos cardíacos ou não. Caso contrário, ele declara que o processo está no estado de deadlock e envia SIGABORT para ele.

Eu só queria compartilhar esse potencial com referência à pergunta feita.

Fooo
fonte
0

Darei minha resposta de uma perspectiva de programação competitiva (cp) , mas ela também se aplica a outros domínios.

Muitas vezes ao fazer cp, as restrições são bastante grandes.

Por exemplo : eu tive uma pergunta com variáveis N, M, Qcomo essa 1 ≤ N, M, Q < 10^5.

O erro que eu estava fazendo era eu declarei um 2D inteiro matriz de tamanho 10000 x 10000em C++e lutou com o SIGABRTerro na Codechef por quase 2 dias.

Agora, se calcularmos:

Tamanho típico de um número inteiro: 4 bytes

Nº de células em nossa matriz: 10000 x 10000

Tamanho total (em bytes): 400000000 bytes = 4 * 10 ^ 8 ~ 400 MB

Suas soluções para essas perguntas funcionarão no seu PC (nem sempre), pois podem suportar esse tamanho.

Mas os recursos nos sites de codificação (juízes on-line) são limitados a poucos KBs.

Portanto, o SIGABRTerro e outros erros desse tipo.

Conclusão:

Em tais perguntas, não devemos declarar uma matriz ou vetor ou qualquer outro DS desse tamanho, mas nossa tarefa é tornar nosso algoritmo tão eficiente que funcione sem eles (DS) ou com menos memória.

PS : Pode haver outros motivos para esse erro; acima foi um deles.

Gênio
fonte