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


202

Які сценарії, коли процес отримує SIGABRT в C ++? Чи завжди цей сигнал надходить зсередини процесу чи цей сигнал може передаватися від одного процесу до іншого?

Чи існує спосіб визначити, який процес надсилає цей сигнал?


3
Є кілька способів. Найпростіший спосіб, якщо ви написали програму, - це зареєструвати обробник сигналу для SIGABRT, який виводить цю інформацію та видаляє її потоки перед поверненням. Другий найпростіший спосіб - це запускати програму в межах напруги. Третій найпростіший спосіб - переконатися, що програма генерує основний файл, коли він виходить з ладу, і виявити це через дамп ядра.
Парфянський розстріл

Відповіді:


195

abort()посилає процес виклику SIGABRTсигнал. Це в abort()основному працює.

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


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

Якщо у мене десь у коді захований чистий віртуальний виклик функції з конструктора, чи може це також закінчитися сигналом SIGABRT? Я запитую, коли я бачу помилку, вказуючи, що у мене є чистий віртуальний дзвінок, і наступний рядок дає мені повідомлення SIGABRT, і додаток або виходить з ладу, або закривається операційною системою. Дякую.
Хрвойо

2
У MacOS ми отримали SIGABRT для відкриття близько 1000 файлових ручок без їх закриття. Замість знущань наші тести абстрагували файл із більш загальним типом зчитувача, який не має Close()методу, тому його забули. Хоча мав чудове покриття. : rolleyes:
Zyl

51

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

Є ще одна проста причина у випадку c ++.

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 від себе: Хрвойо згадав про похований чистий віртуальний виклик із 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 ++ -o aa 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

контрольний код:

бед 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.

Помилкою, яку я робив, було те, що я оголосив двомірний цілочисельний масив розміру 10000 x 10000в C++і боровся зSIGABRT помилкою в Codechef майже 2 дні.

Тепер, якщо ми порахуємо:

Типовий розмір цілого числа: 4 байти

Кількість комірок у нашому масиві: 10000 x 10000

Загальний розмір (у байтах): 400000000 байт = 4 * 10 ^ 8 ≈ 400 МБ

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

Але ресурси на сайтах кодування (онлайн-судді) обмежені кількома КБ.

Отже, SIGABRTпомилка та інші подібні помилки.

Висновок:

У таких питаннях нам не слід оголошувати масив, вектор або будь-яку іншу DS такого розміру, але наше завдання - зробити наш алгоритм настільки ефективним, що він працює без них (DS) або з меншою пам’яттю.

PS : Можуть бути й інші причини цієї помилки; нагорі був один із них.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.