SIGABRT 和 SIGSEGV 有啥区别

Posted

技术标签:

【中文标题】SIGABRT 和 SIGSEGV 有啥区别【英文标题】:What is the difference between SIGABRT and SIGSEGVSIGABRT 和 SIGSEGV 有什么区别 【发布时间】:2019-01-22 07:34:23 【问题描述】:

我用下面的两段代码做了核心转储错误:

//test.cpp
int main()

    int *p = new int;
    *p = 100;
    delete p;
    delete p;
    return 0;


//test2.cpp
int main()

    int *p = new int;
    *p = 100;
    delete p;
    *p = 111;
    std::cout<<*p<<std::endl;
    return 0;

Gdb 告诉我,第一段代码因为信号 SIGABRT 而被核心转储,而第二段代码因为信号 SIGSEGV 而被核心转储。

你能说一下有什么区别吗?

【问题讨论】:

这里很好地列出了各种信号的含义:en.cppreference.com/w/c/program/SIG_types 该问题中没有任何内容是 C。请在以后的问题中选择标签时更加小心。 两个 sn-ps 都有未定义的行为,可能会导致任何这些信号,或者根本没有。所以他们没有展示任何东西 @VTT 讨论一下为什么每个都是 UB,这将是一个很好的答案。 关于为什么每个都是UB的解释可以在较老的问题中找到,与本题的标题无关。 【参考方案1】:

SIGABRT 被 delete 的实现明确检测到并发出信号,该实现检测到第二次删除无效。它通过调用abort函数来启动

SIGSEGV 不同,它是正在进行,而不是像以前那样通过库中的检查来检测,它是通过操作系统的内存管理启动的

见https://en.cppreference.com/w/c/program/SIG_types

【讨论】:

我看到你从第一条评论中复制了链接,但其余的答案只是试图解释 UB @VTT所有检测方式的区别 @VTT 而不是仅仅批评,请提出你的答案,让我们所有人都知道什么是真正的答案;-) @bruno 建设性的批评是好事。我相信 VTT 正在努力帮助您解决问题,而不是伤害它...... @FantasticMrFox 是的,当然,我很讽刺。但是你自己注意不要把他的名字写得很糟糕,他是VTT而不是CTT(这是一个笑话,你们两个都不要那么坏^^)。 哦,你更正了【参考方案2】:

这两个例子都是未定义的行为,这意味着根据 c++,编译器(和系统)可以做任何它想做的事情。

在情况 1 中,可能会检查指针的双重删除,因此会发出 SIGABRT 信号。 SIGABRT 表示异常终止条件,例如由 abort() 发起。 在情况 2 中,系统检测到您对已删除指针的尊重,并且 创建一个SIGSEGV 信号。 SIGSEGV 表示无效的内存访问(分段错误)

但两者仍然是 UB,所以这只是您当前编译器/操作系统/系统的一个功能。从错误here 的定义中可以清楚地看出错误之间的区别。一种是中止,通常由编译器或编码器生成。一种是由无效的内存访问引起的,通常由操作系统或硬件发出信号。

【讨论】:

这也不能解释 SIGABRT 和 SIGSEGV 之间的区别 @VTT 感谢您的提示。【参考方案3】:

两次删除指针是未定义的行为,这意味着任何事情都可能发生。在这种情况下,它会导致发出SIGABRT 信号。

访问不属于程序的内存也是未定义的行为,在这种情况下会导致分段错误并发出SIGSEGV

SIGABRT 表示程序本身检测到的错误,并通过调用abort 报告。 SIGSEGV 表示对有效内存的无效访问。

【讨论】:

以上是关于SIGABRT 和 SIGSEGV 有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mono 的 C# 代码中的间歇性 SIGSEGV (segfault)、SIGABRT 和进程挂起

kill命令

如何在多线程环境中捕获 SIGABRT?

exit() 和 abort() 有啥区别?

为啥我不能忽略 SIGSEGV 信号?

使用 Qt 的多线程应用程序有啥问题(错误 SIGSEGV)