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


202

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

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


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

Ответы:


195

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

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


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

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

2
На MacOS мы получили SIGABRT для открытия около 1000 файловых дескрипторов без их закрытия. Вместо насмешек наши тесты абстрагировали файл с более общим типом читателя, у которого нет Close()метода, поэтому он был забыт. Был отличный охват, хотя. : Rolleyes:
Зил

52

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

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

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


49

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

kill -SIGABRT 30823

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

$ /bin/dash
$ Aborted

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

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


17

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

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


14

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

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

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

thread::join();

или

thread::detach();

7

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

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

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


4

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

компилировать: g ++ -a aa aa.cpp

ulimit -c неограниченно

запустить: ./aa

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

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

gdb aa core

смотри regs:

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 sig = 6 = SIGABRT

:)


2

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

string x[5];

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

    cin>>x[i];

}

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


1

Как метко указано «@sarnold», любой процесс может отправлять сигнал любому другому процессу, следовательно, один процесс может отправлять SIGABORT другому процессу, и в этом случае принимающий процесс не может различить, приходит ли он из-за собственной настройки память и т. д., или кто-то еще «одноадресно», отправьте на него.

В одной из систем, с которой я работал, есть один тупиковый детектор, который фактически определяет, выходит ли процесс из какой-либо задачи, с помощью биения сердца или нет. Если нет, то он объявляет, что процесс находится в тупиковом состоянии, и отправляет SIGABORT.

Я просто хотел поделиться этой перспективой со ссылкой на заданный вопрос.


0

Я дам свой ответ с точки зрения конкурентного программирования (cp) , но это относится и к другим областям.

Много раз при выполнении команды cp ограничения достаточно велики.

Например : у меня был вопрос с N, M, Qтакими переменными , что 1 ≤ N, M, Q < 10^5.

Ошибка , которую я делал я был объявлен 2D массив целых чисел размером 10000 x 10000в C++и боролись сSIGABRT ошибкой в Codechef в течение почти 2 дней.

Теперь, если мы посчитаем:

Типичный размер целого числа: 4 байта

Количество ячеек в нашем массиве: 10000 х 10000

Общий размер (в байтах): 400000000 байт = 4 * 10 ^ 8 ≈ 400 МБ

Ваши решения таких вопросов будут работать на вашем компьютере (не всегда), поскольку он может позволить себе такой размер.

Но ресурсы на сайтах кодирования (онлайн-судьи) ограничены несколькими килобайтами.

Отсюда и SIGABRTошибки и другие подобные ошибки.

Вывод:

В таких вопросах нам не следует объявлять массив, вектор или любой другой DS такого размера, но наша задача - сделать наш алгоритм настолько эффективным, чтобы он работал без них (DS) или с меньшим объемом памяти.

PS : могут быть и другие причины этой ошибки; выше был один из них.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.