进程何时获得SIGABRT(信号6)?

时间:2010-08-05 09:00:18

标签: c++ sigabrt

进程在C ++中获取SIGABRT的场景是什么?此信号是否始终来自过程中,或者此信号是否可以从一个过程发送到另一个过程?

有没有办法确定哪个进程正在发送此信号?

11 个答案:

答案 0 :(得分:164)

abort()向调用进程发送SIGABRT信号,这就是abort()基本上如何工作的方式。

abort()通常由库函数调用,它检测内部错误或严重破坏的约束。例如,malloc()如果其内部结构被堆溢出损坏,将调用abort()

答案 1 :(得分:49)

您可以使用kill(2)界面向任何流程发送任何信号:

kill -SIGABRT 30823

30823是我开始的dash进程,因此我可以轻松找到我想要杀死的进程。

$ /bin/dash
$ Aborted

Aborted输出显然是dash报告SIGABRT的方式。

可以使用kill(2)将其直接发送到任何流程,或者流程可以通过assert(3)abort(3)raise(3)将信号发送给自己。

答案 2 :(得分:46)

libc和其他库通常使用

SIGABRT在发生严重错误时中止程序。例如,如果检测到双重释放或其他堆损坏,glibc会发送SIGABRT

此外,大多数assert实现在断言失败的情况下使用SIGABRT

此外,SIGABRT可以像任何其他信号一样从任何其他进程发送。当然,发送过程需要以相同的用户或root身份运行。

答案 3 :(得分:16)

通常在内存分配出现问题时发生。

当我的程序试图分配一个时,它发生在我身上 负数大小的数组。

答案 4 :(得分:10)

对于c ++,还有另一个简单的原因。

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

即。线程范围已结束,但您忘记调用

thread::join();

thread::detach();

答案 5 :(得分:6)

GNU libc会在调用ad=new AlertDialog.Builder(MainActivity.this); final AlertDialog ab=ad.create(); ad.setCancelable(false); ad.setMessage("YOUR_MESSAGE"); ad.setPositiveButton("OK",new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ab.cancel(); } }); ad.show(); (然后触发/dev/tty之前)向abort()打印有关某些致命条件的信息,但如果您将程序作为服务运行或否则不会在真正的终端窗口中,这些消息可能会丢失,因为没有tty来显示消息。

请参阅我关于重定向libc以写入stderr而不是/ dev / tty的帖子:

Catching libc error messages, redirecting from /dev/tty

答案 6 :(得分:3)

进程从自身获取SIGABRT的情况: Hrvoje提到了从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 unlimited

运行:./ 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

:)

答案 7 :(得分:1)

就我而言,这是由于数组中的输入索引等于数组的长度。

string x[5];

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

    cin>>x[i];

}
正在访问

x [5],但不存在。

答案 8 :(得分:0)

我将从竞争性编程(cp)的角度给出答案,但它也适用于其他领域。

执行cp时很多次,约束很大。

例如:我有一个变量为 N, M, Q 的问题,以致 {{1 }}

我犯的错误是我在1 ≤ N, M, Q < 10^5中声明了一个大小为10000 x 10000的2D整数数组,并在Codechef上遇到了 C++ 错误,将近2天。

现在,如果我们计算:

  

整数的典型大小:4个字节

     

不。数组中的单元数:10000 x 10000

     

总大小(以字节为单位):400000000字节= 4 * 10 ^ 8≈400 MB

您的此类问题的解决方案将在您的PC上运行(并非总是如此),因为它可以承受这种大小。

但是编码站点(在线裁判)上的资源仅限于几个KB。

因此,SIGABRT错误和其他此类错误。

结论:

在这样的问题中,我们不应该声明一个数组或向量或任何其他大小的DS,但是我们的任务是使我们的算法高效,使其在没有它们(DS)或内存较少的情况下也可以工作。

PS :可能还有其他原因导致此错误;以上就是其中之一。

答案 9 :(得分:0)

正如“ @sarnold”,恰当地指出,任何进程都可以向其他进程发送信号,因此,一个进程可以将SIGABORT发送给其他进程,并且在这种情况下,接收进程由于它的存在而无法区分其是否到来自己进行内存调整等,或者其他人“单播”发送给它。

在我工作的其中一个系统中,有一个死锁检测器,它实际上通过给出心跳来检测进程是否由于某些任务而结束。如果不是,那么它将声明该进程处于死锁状态,并向其发送SIGABORT。

我只是想参考提出的问题来分享这个预期。

答案 10 :(得分:0)

关于第一个问题:What are the scenarios where a process gets a SIGABRT in C++?

我可以想到两种特殊情况,即 C++ 程序自动中止——不是通过直接调用 std::abort()std::terminate()

一:在处理异常时抛出异常。

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

二:试图在 main() 之外传播的未捕获异常。

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

C++ 专家可能会说出更多特殊情况。

这些参考页面上也有很多很好的信息: