2010-08-05 3 views
133

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

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

+2

Есть несколько способов. Самый простой способ, если вы написали программу, - зарегистрировать обработчик сигналов для SIGABRT, который распечатывает эту информацию и очищает свои потоки перед возвратом. Второй самый простой способ - запустить программу в рамках strace. Третий самый простой способ - обеспечить, чтобы программа генерировала основной файл, когда он сбой, и узнайте через дамп ядра. –

ответ

134

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

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

+14

для меня в большинстве случаев SIGABRT был отправлен 'libc', пытаясь называть' free() 'на неинициализированном/поврежденном указателе – grandrew

+0

Если бы я где-то в коде, похоронил чистый вызов виртуальной функции внутри конструктора, мог бы также заканчивается сигналом SIGABRT? Я спрашиваю, как я вижу ошибку, заявив, что у меня есть чистый виртуальный вызов, а следующая строка дает мне сообщение SIGABRT, и приложение либо выходит из строя, либо закрывается операционной системой. Благодарю. – Hrvoje

44

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

kill -SIGABRT 30823

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

$ /bin/dash 
$ Aborted 

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

Он может быть направлен непосредственно к любому процессу с использованием kill(2), или процесс может послать сигнал на себе с помощью assert(3), abort(3) или raise(3).

37

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

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

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

12

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

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

3

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

См мой пост на перенаправлении Libc написать стандартный вывод вместо/Dev/TTY:

Catching libc error messages, redirecting from /dev/tty

6

Там еще один простой причина в случае с ++.

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

i.e.Объем нить закончилась, но вы забыли назвать либо

thread::join(); 

или

thread::detach(); 
1

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

string x[5]; 

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

    cin>>x[i]; 

} 

x [5] обращается к которому нет.

2

Случай, когда процесс получает SIGABRT от себя: Hrvoje упомянул о захороненном чистом виртуальном существе, вызванном из ctor, производящем прерывание, я воссоздал пример для этого. Здесь, когда d должен быть сконструирован, он сначала вызывает свой базовый класс A 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; 
} 

компиляции: г ++ -o аа aa.cpp

ULIMIT -c неограниченная

пробег: ./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 $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 сиг = 6 = SIGABRT

:)