When does a process get SIGABRT (signal 6)?
Asked Answered
A

14

292

What are the scenarios where a process gets a SIGABRT in C++? Does this signal always come from within the process or can this signal be sent from one process to another?

Is there a way to identify which process is sending this signal?

Adventitious answered 5/8, 2010 at 9:0 Comment(1)
There are a couple ways. The easiest way, if you wrote the program, is to register a signal handler for SIGABRT that prints out that information and flushes its streams before returning. The second easiest way is to run the program within strace. The third easiest way is to ensure the program generates a core file when it crashes, and find out via the core dump.Protractile
A
282

abort() sends the calling process the SIGABRT signal, this is how abort() basically works.

abort() is usually called by library functions which detect an internal error or some seriously broken constraint. For example malloc() will call abort() if its internal structures are damaged by a heap overflow.

Asare answered 5/8, 2010 at 9:6 Comment(3)
for me in most cases SIGABRT was sent by libc trying to call free() on a non-initialized/corrupted pointerSappington
If I have somewhere in the code, buried pure virtual function call from within the constructor, could that also end up with the SIGABRT signal? I am asking as I am seeing an error stating that I have a pure virtual call, and the next line gives me a SIGABRT message and the application either crashes or is closed by the operating system. Thanks.Buck
On MacOS, we got SIGABRT for opening about 1000 file handles without closing them. Instead of mocking, our tests abstracted the file with a more generic reader type, which has no Close() method, so it was forgotten. Had great coverage though. :rolleyes:Esquivel
R
72

SIGABRT is commonly used by libc and other libraries to abort the program in case of critical errors. For example, glibc sends an SIGABRT in case of a detected double-free or other heap corruptions.

Also, most assert implementations make use of SIGABRT in case of a failed assert.

Furthermore, SIGABRT can be sent from any other process like any other signal. Of course, the sending process needs to run as same user or root.

Russelrussell answered 5/8, 2010 at 9:8 Comment(0)
N
53

You can send any signal to any process using the kill(2) interface:

kill -SIGABRT 30823

30823 was a dash process I started, so I could easily find the process I wanted to kill.

$ /bin/dash
$ Aborted

The Aborted output is apparently how dash reports a SIGABRT.

It can be sent directly to any process using kill(2), or a process can send the signal to itself via assert(3), abort(3), or raise(3).

Noach answered 5/8, 2010 at 9:6 Comment(0)
P
22

It usually happens when there is a problem with memory allocation.

It happened to me when my program was trying to allocate an array with negative size.

Peirce answered 7/10, 2011 at 16:57 Comment(0)
D
19

There's another simple cause in case of c++.

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

i.e. scope of thread ended but you forgot to call either

thread::join();

or

thread::detach();
Dioptase answered 10/3, 2016 at 8:17 Comment(0)
E
9

The GNU libc will print out information to /dev/tty regarding some fatal conditions before it calls abort() (which then triggers SIGABRT), but if you are running your program as a service or otherwise not in a real terminal window, these message can get lost, because there is no tty to display the messages.

See my post on redirecting libc to write to stderr instead of /dev/tty:

Catching libc error messages, redirecting from /dev/tty

Electroshock answered 17/8, 2015 at 18:31 Comment(0)
T
5

A case when process get SIGABRT from itself: Hrvoje mentioned about a buried pure virtual being called from ctor generating an abort, i recreated an example for this. Here when d is to be constructed, it first calls its base class A ctor, and passes inside pointer to itself. the A ctor calls pure virtual method before table was filled with valid pointer, because d is not constructed yet.

#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;
}

compile: g++ -o aa aa.cpp

ulimit -c unlimited

run: ./aa

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

now lets quickly see the core file, and validate that SIGABRT was indeed called:

gdb aa core

see regs:

i r
rdx            0x6      6
rsi            0x69a    1690
rdi            0x69a    1690
rip            0x7feae3170c37

check code:

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

:)

Therewith answered 29/3, 2017 at 8:20 Comment(0)
S
3

The error munmap_chunk invalid pointer also causes a SIGABRT and in my case it was very hard to debug as I was not using pointers at all. It turned out that it was related to std::sort().

std::sort() requires a compare function that creates a strict weak ordering! That means both comparator(a, b) and comparator(b, a) must return false when a==b holds. (see https://en.cppreference.com/w/cpp/named_req/Compare) In my case I defined the operator< in my struct like below:

bool operator<(const MyStruct& o) const {
    return value <= o.value; // Note the equality sign
}

and this was causing the SIGABRT because the function does not create a strict weak ordering. Removing the = solved the problem.

Skyrocket answered 19/7, 2022 at 14:45 Comment(0)
K
2

In my case, it was due to an input in an array at an index equal to the length of the array.

string x[5];

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

    cin>>x[i];

}

x[5] is being accessed which is not present.

Knuckle answered 3/11, 2016 at 17:53 Comment(0)
G
1

I will give my answer from a competitive programming(cp) perspective, but it applies to other domains as well.

Many a times while doing cp, constraints are quite large.

For example : I had a question with a variables N, M, Q such that 1 ≤ N, M, Q < 10^5.

The mistake I was making was I declared a 2D integer array of size 10000 x 10000 in C++ and struggled with the SIGABRT error at Codechef for almost 2 days.

Now, if we calculate :

Typical size of an integer : 4 bytes

No. of cells in our array : 10000 x 10000

Total size (in bytes) : 400000000 bytes = 4*10^8 ≈ 400 MB

Your solutions to such questions will work on your PC(not always) as it can afford this size.

But the resources at coding sites(online judges) is limited to few KBs.

Hence, the SIGABRT error and other such errors.

Conclusion:

In such questions, we ought not to declare an array or vector or any other DS of this size, but our task is to make our algorithm such efficient that it works without them(DS) or with less memory.

PS : There might be other reasons for this error; above was one of them.

Guatemala answered 8/10, 2019 at 18:44 Comment(0)
I
1

As "@sarnold", aptly pointed out, any process can send signal to any other process, hence, one process can send SIGABORT to other process & in that case the receiving process is unable to distinguish whether its coming because of its own tweaking of memory etc, or someone else has "unicastly", send to it.

In one of the systems I worked there is one deadlock detector which actually detects if process is coming out of some task by giving heart beat or not. If not, then it declares the process is in deadlock state and sends SIGABORT to it.

I just wanted to share this prospective with reference to question asked.

Insuperable answered 30/10, 2019 at 12:32 Comment(0)
L
1

Regarding the first question: What are the scenarios where a process gets a SIGABRT in C++?

I can think of two special cases where a C++ program is aborted automatically -- not by directly calling std::abort() or std::terminate():

One: Throw an exception while an exception is being handled.

try {
    throw "abc";
}
catch (...) {
    throw "def";  // abort here
}

Two: An uncaught exception that attempts to propagates outside main().

int main(int argc, char** argv)
{
    throw "abc";  // abort here
}

C++ experts could probably name more special cases.

There is also a lot of good info on these reference pages:

Leighton answered 21/12, 2020 at 19:23 Comment(1)
Throwing an exception from within a catch(...) is perfectly legal. What is NOT OK is throwing an exception from a destructor of a stack variable during the stack unwind for exception processing. That will lead to an immediate terminate() call.Venicevenin
S
1

For Android native code, here are some reasons abort is called according to https://source.android.com/devices/tech/debug/native-crash :

Aborts are interesting because they are deliberate. There are many different ways to abort (including calling abort(3), failing an assert(3), using one of the Android-specific fatal logging types), but all involve calling abort.

Sleave answered 31/8, 2021 at 20:49 Comment(0)
R
0

In my case I was getting SIGABRT with code SI_QUEUE when allocating memory in loop. I think I was doing it properly and safely using nothrow:

uint8_t* ptr = new(std::nothrow) uint8_t[allocationSize];
if (ptr == nullptr) {
    break;
}

but system didn't like it and killed my app. Behavior might depend on system, in my case I was running this code on Android emulator.

Rationalism answered 11/3 at 16:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.