Каковы сценарии, когда процесс получает SIGABRT в С++? Всегда ли этот сигнал поступает из процесса или может ли этот сигнал посылаться из одного процесса в другой?
Есть ли способ определить, какой процесс отправляет этот сигнал?
Каковы сценарии, когда процесс получает SIGABRT в С++? Всегда ли этот сигнал поступает из процесса или может ли этот сигнал посылаться из одного процесса в другой?
Есть ли способ определить, какой процесс отправляет этот сигнал?
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.
Обычно это происходит, когда есть проблема с выделением памяти.
Это случилось со мной, когда моя программа пыталась выделить массив с отрицательным размером.
Есть еще одна простая причина в случае С++.
std::thread::~thread{
if((joinable ())
std::terminate ();
}
то есть. объем потока закончился, но вы забыли позвонить либо
thread::join();
или
thread::detach();
GNU libc будет распечатывать информацию в /dev/tty
относительно некоторых фатальных условий до того, как он вызовет abort()
(который затем вызывает SIGABRT
), но если вы запускаете свою программу как услугу или иначе не находитесь в реальном терминале окно, это сообщение может потеряться, потому что нет сообщений tty для отображения сообщений.
См. мой пост по перенаправлению libc для записи в stderr вместо /dev/tty:
Случай, когда процесс получает SIGABRT от себя: Хрвое упомянул о захороненном чистом виртуальном существе, вызванном из 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;
}
скомпилировать: g++ -o aa aa.cpp
ulimit -c неограниченный
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 $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
:)
В моем случае это произошло из-за ввода в массив с индексом, равным длине массива.
string x[5];
for(int i=1; i<=5; i++){
cin>>x[i];
}
x [5], к которому нет доступа.
Я дам свой ответ с точки зрения конкурентного программирования (cp), но он применим и к другим доменам.
Во многих случаях при выполнении cp ограничения довольно велики.
Например,: у меня был вопрос с переменными N, M, Q
, такими, что 1 ≤ N, M, Q < 10^5
.
Ошибка, которую я совершил, заключалась в том, что я объявил двумерный целочисленный массив размером 10000 x 10000
в C++
и боролся с ошибкой SIGABRT
в Codechef в течение почти 2 дней.
Теперь, если мы посчитаем:
Типичный размер целого числа: 4 байта
No. of cells in our array: 10000 x 10000
Total size (in bytes): 400000000 bytes = 4*10^8 ≈ 400 MB
Ваши решения таких вопросов будут работать на вашем компьютере (не всегда), поскольку он может позволить себе такой размер.
Но ресурсы на сайтах кодирования (онлайн-судьи) ограничены несколькими килобайтами.
Следовательно, ошибка SIGABRT
и другие подобные ошибки.
Вывод:
В таких вопросах нам не следует объявлять массив, вектор или любой другой DS такого размера, но наша задача - сделать наш алгоритм настолько эффективным, чтобы он работал без них (DS) или с меньшим объемом памяти.
PS: возможны другие причины этой ошибки; выше был один из них.