Які сценарії, коли процес отримує SIGABRT в C ++? Чи завжди цей сигнал надходить зсередини процесу чи цей сигнал може передаватися від одного процесу до іншого?
Чи існує спосіб визначити, який процес надсилає цей сигнал?
Які сценарії, коли процес отримує SIGABRT в C ++? Чи завжди цей сигнал надходить зсередини процесу чи цей сигнал може передаватися від одного процесу до іншого?
Чи існує спосіб визначити, який процес надсилає цей сигнал?
Відповіді:
abort()
посилає процес виклику SIGABRT
сигнал. Це в abort()
основному працює.
abort()
зазвичай викликається функціями бібліотеки, які виявляють внутрішню помилку або якесь серйозно порушене обмеження. Наприклад malloc()
, зателефонуйте, abort()
якщо його внутрішні структури пошкоджені куповим переливом.
libc
намагаючись зателефонувати free()
за неініціалізованим / пошкодженим покажчиком
Close()
методу, тому його забули. Хоча мав чудове покриття. : rolleyes:
SIGABRT
зазвичай використовується libc та іншими бібліотеками для переривання програми у випадку критичних помилок. Наприклад, glibc надсилає дані SIGABRT
у випадку виявлення подвійних або інших пошкоджень купи.
Крім того, більшість assert
реалізацій використовують SIGABRT
у випадку невдалого ствердження.
Крім того, SIGABRT
може надсилатися з будь-якого іншого процесу, як і будь-який інший сигнал. Звичайно, процес надсилання потрібно запускати як той самий користувач або root.
Ви можете надіслати будь-який сигнал до будь-якого процесу за допомогою kill(2)
інтерфейсу:
kill -SIGABRT 30823
30823 був dash
процес, який я розпочав, тому я міг легко знайти процес, який хотів убити.
$ /bin/dash
$ Aborted
Aborted
Вихід, по- видимому , як dash
повідомляє SIGABRT.
Він може бути спрямований безпосередньо до будь-якого процесу , використовуючи kill(2)
, або процес може послати сигнал на собі з допомогою assert(3)
, abort(3)
або raise(3)
.
Є ще одна проста причина у випадку 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 від себе: Хрвойо згадав про похований чистий віртуальний виклик із 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
:)
Як влучно зазначав "@sarnold", будь-який процес може надсилати сигнал до будь-якого іншого процесу, отже, один процес може відправити SIGABORT до іншого процесу, і в цьому випадку процес прийому не в змозі визначити, чи надходить його через власне налаштування пам'ять тощо, або хтось інший має "недоброзичливо", надішліть йому.
В одній із систем, в яких я працював, є один детектор тупикового зв'язку, який фактично виявляє, чи виникає процес із якогось завдання, даючи серцебиття чи ні. Якщо ні, то він оголошує процес у глухому стані та надсилає до нього SIGABORT.
Я просто хотів поділитися цим потенційним посиланням на задане питання.
Я дам свою відповідь з точки зору конкурентного програмування (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 : Можуть бути й інші причини цієї помилки; нагорі був один із них.