进程在C ++中获取SIGABRT的场景是什么?此信号是否始终来自过程中,或者此信号是否可以从一个过程发送到另一个过程?
有没有办法确定哪个进程正在发送此信号?
答案 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)
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的帖子:
答案 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++ 专家可能会说出更多特殊情况。
这些参考页面上也有很多很好的信息: