Когда процесс получает SIGABRT (сигнал 6)?

каковы сценарии, в которых процесс получает SIGABRT в C++? Всегда ли этот сигнал поступает из процесса или может быть отправлен из одного процесса в другой?

есть ли способ определить, какой процесс посылает этот сигнал?

8 ответов


abort() отправляет вызывающий процесс SIGABRT сигнал, это как abort() в основном работает.

abort() обычно вызывается библиотечными функциями, которые обнаруживают внутреннюю ошибку или какое-либо серьезно нарушенное ограничение. Например malloc() будем называть abort() если его внутренние структуры повреждены переполнение кучи.


вы можете отправить любой сигнал в любой процесс, используя kill(2) интерфейс:

kill -SIGABRT 30823

30823 был dash процесс я начал, поэтому я мог легко найти процесс, который я хотел убить.

$ /bin/dash
$ Aborted

на Aborted выход, по-видимому, как dash сообщает SIGABRT.

его можно отправить сразу в любой процесс используя kill(2), или процесс может отправить сигнал себе через assert(3), abort(3) или raise(3).


SIGABRT обычно используется libc и другими библиотеками для прерывания программы в случае критических ошибок. Например, glibc отправляет SIGABRT в случае обнаруженных двойн-свободных или других повреждений кучи.

кроме того, большинство assert реализации используют SIGABRT в случае не утверждать.

кроме того, SIGABRT может быть отправлен из любого другого процесса, как и любой другой сигнал. Конечно, процесс отправки должен выполняться как тот же пользователь или root.


обычно это происходит, когда возникает проблема с выделением памяти.

Это случилось со мной, когда я моя программа пытается выделить массив с отрицательным размером.


есть еще одна простая причина в случае c++.

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

т. е. область потока закончилась, но вы забыли позвонить либо

thread::join();

или

thread::detach();

GNU libc распечатает информацию в /dev/tty по какой-то роковой условия перед вызовом abort() (который затем инициирует SIGABRT), но если вы используете свою программу как службу или иначе не в реальном окне терминала, это сообщение может потеряться, потому что нет tty для отображения сообщений.

см. мой пост о перенаправлении libc для записи в stderr вместо /dev/tty:

ловить сообщения об ошибках libc, перенаправляя из / dev / tty


случай, когда процесс получает SIGABRT от себя: Hrvoje упомянул о похороненном чистом виртуальном существе, вызванном из ctor, генерирующего аборт, я воссоздал пример для этого. Вот когда будет построен, он сначала вызывает конструктор своего базового класса, и передает внутрь указатель на себя. a ctor вызывает чистый виртуальный метод до заполнения таблицы допустимым указателем, потому что d еще не построен.

#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;
}

compile: g++ - o aa aa.cpp

параметр ulimit -с неограниченный

run: ./ aa

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

теперь позволяет быстро увидеть основной файл и проверить, что SIGABRT действительно назывался:

gdb aa core

см. правила:

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

проверить код:

disas 0x7feae3170c37

mov    xea,%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

:)


в моем случае это было связано с входом в массив с индексом, равным длине массива.

string x[5];

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

    cin>>x[i];

}

x[5] доступен, которого нет.