249

进程在 C++ 中获得 SIGABRT 的场景有哪些?这个信号是否总是来自进程内部,或者这个信号可以从一个进程发送到另一个进程?

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

4

12 回答 12

240

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

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

于 2010-08-05T09:06:28.273 回答
60

SIGABRTlibc 和其他库通常使用它来在出现严重错误时中止程序。例如,glibcSIGABRT在检测到双释放或其他堆损坏的情况下发送一个。

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

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

于 2010-08-05T09:08:45.357 回答
53

kill(2)您可以使用该接口向任何进程发送任何信号:

kill -SIGABRT 30823

30823 是dash我启动的一个进程,所以我可以很容易地找到我想杀死的进程。

$ /bin/dash
$ Aborted

Aborted输出显然是如何报告dashSIGABRT。

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

于 2010-08-05T09:06:24.683 回答
19

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

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

于 2011-10-07T16:57:33.783 回答
17

在 c++ 的情况下还有另一个简单的原因。

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

即线程范围结束,但你忘了打电话

thread::join();

或者

thread::detach();
于 2016-03-10T08:17:20.130 回答
9

/dev/ttyGNU libc 会在调用之前打印出有关某些致命情况的信息abort()(然后触发SIGABRT),但是如果您将程序作为服务运行或者不在真正的终端窗口中运行,这些消息可能会丢失,因为没有tty 来显示消息。

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

捕获 libc 错误消息,从 /dev/tty 重定向

于 2015-08-17T18:31:15.653 回答
5

进程从自身获取 SIGABRT 的情况:Hrvoje 提到了从 ctor 调用一个隐藏的纯虚拟来生成中止,我为此重新创建了一个示例。在这里,当要构造 d 时,它首先调用其基类 A ctor,并将内部指针传递给自身。A ctor 在 table 被有效指针填充之前调用纯虚方法,因为 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

校验码:

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

:)

于 2017-03-29T08:20:11.270 回答
2

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

string x[5];

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

    cin>>x[i];

}

正在访问不存在的 x[5]。

于 2016-11-03T17:53:40.297 回答
1

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

很多时候在做cp时,约束是相当大的。

例如:我有一个关于变量的N, M, Q问题1 ≤ N, M, Q < 10^5

我犯的错误是我声明了一个大小10000 x 10000为 in的 2D 整数数组,C++SIGABRT在 Codechef 中为该错误苦苦挣扎了将近 2 天。

现在,如果我们计算:

整数的典型大小:4 字节

我们阵列中的单元数:10000 x 10000

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

您对此类问题的解决方案将适用于您的 PC(并非总是),因为它可以承受这种尺寸。

但是编码站点(在线评委)的资源仅限于几 KB。

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

结论:

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

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

于 2019-10-08T18:44:01.420 回答
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.

于 2019-10-30T12:32:06.277 回答
1

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

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

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

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

二:试图传播到外部的未捕获异常main()

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

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

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

于 2020-12-21T19:23:05.820 回答
0

对于 Android 原生代码,以下是根据https://source.android.com/devices/tech/debug/native-crash调用 abort 的一些原因:

中止很有趣,因为它们是故意的。有许多不同的中止方法(包括调用abort(3) ,使assert(3)失败,使用 Android 特定的致命日志记录类型之一),但都涉及调用 abort。

于 2021-08-31T20:49:13.250 回答