当`kill`生成时,SIGSEGV是否特殊?

时间:2014-01-26 08:16:18

标签: c++ segmentation-fault signals posix kill

我知道当内核使用它来报告内存访问冲突时,SIGSEGV不能被忽略。但是,如果我为SIGSEGV安装一个什么都不做的信号处理程序,然后另一个进程使用kill向我发送该信号,那么这个行为就像我使用了“正常”信号一样(如SIGUSR1)而不是?

3 个答案:

答案 0 :(得分:2)

  

我有接收信号SIGSEGV但没有做任何事情的功能,这是否意味着信号被忽略了?

是的,你抓住了信号SIGSEGV并且在处理程序中没有做任何事情,控制返回。

一般而言,忽略真实的SIGSEGV并不意味着错误不会使程序能够继续有意义地执行。注意SIGSEGV不是通过用户请求发送的信号(某些键组合),当程序试图在为其分配的内存之外读取或写入时,SIGSEGV会引发。该名称是“分段违规”的缩写。

  

SIG35-C. Do not return from a computational exception signal handler

     

根据C标准,子条款7.14.1.1 ISO/IEC 9899:2011,如果作为计算结果输入信号处理程序   异常(即,使用其参数SIGFPE的值,SIGILL,   或SIGSEGV或任何其他实现定义的值对应   返回时,行为是未定义的。

     

忽略SIGFPE后,进程的行为未定义,   SIGILLSIGSEGVSIGBUS 信号不是由...生成的   kill()sigqueue()raise()

第二

  

信号是否传递给默认实现?

不,根据标准报价行为或您的代码未定义,因为kill()生成信号。默认实现将立即终止您的流程执行并生成代码转储(Ref:Standard Signals)。

Zackcomment

  

您的代码具有明确定义的行为 - 将接收信号,即   处理程序将运行,它将什么都不做,控制将恢复正常   流 - 但你仍然应该改变它以使用其他信号。   SIGUSR1SIGUSR2旨在按照您使用的方式使用   SIGSEGV现在,作为内部应用程序消息发送给自己。

GNU C Library是学习Signal Handling的好资源。

答案 1 :(得分:2)

Grijesh Chauhan的答案在技术上是正确的但很难理解,因此我将写出我自己对基本相同点的阐述。用脚注。 0

Dima询问当一个线程为SIGSEGV安装do-nothing处理程序然后另一个线程使用kill 1 在该线程上生成SIGSEGV时会发生什么。一句话答案是处理程序运行,什么都不做,然后控制返回到被中断线程内的正常流程。与内核生成SIGSEGV作为对实际内存访问冲突的响应时不同,此方案 not 触发undefined behavior 2 。但是,SIGSEGV及其朋友(SIGBUSSIGFPESIGILL)的预期目的是让内核告诉您的程序它已经做了如此令人发指的事情必须是一个bug,正常执行无法继续,你想在被杀之前清理一下吗?因此,将它们用于其他任何事情都是不明智的。有几个信号(SIGUSR1SIGUSR2SIGRTMINSIGRTMAX)保留给每个应用程序使用但是它喜欢;你应该使用其中一个。


对于更长的答案,我将从POSIX标准 3 小节Signal Actions开始。首先,四个信号SIGFPESIGILLSIGSEGVSIGBUS与任何其他信号一样,可以异步传送" - 没有特别的时间 - 因为某段代码使用系统调用(例如kill)来生成它们。当发生这种情况时,它们被视为与其默认"动作"的任何其他信号完全相同。碰巧是#34;异常终止程序&#34 ;;请注意,许多其他信号具有此属性,包括为应用程序使用而保留的信号。如果您的计划在SIGFPE和朋友生成SIGILLSIGSEGVSIGBUSkill时只需担心接收sigwaitsignalfdSIGFPESIGILL,则可以执行此操作所有正常的东西:阻塞它们,忽略它们,建立信号处理程序,做任何对异步信号处理程序有效的事情, 4 通过SIGSEGV或{{1}接收它们而不是正常的asynchronous system trap - 类似的传递机制。

然而。 SIGBUSSIGFPESIGILLSIGSEGV也会生成"同步"由内核响应触发硬件异常的不同类型的错误程序行为,例如尝试访问未映射的内存。同步意味着在执行违规CPU指令时,立即传递信号,并且在同一个线程上,而不是在进程中发生任何解除阻塞的线程。我们真的不是在开玩笑地立即开始#34; part:如果有一个信号处理程序,当它执行时,保存的程序计数器将指向导致任何类型的硬件异常的确切指令。内核不允许执行通过导致CPU发出硬件异常的指令,因此POSIX说这是关于尝试丢弃这些信号而不是终止该过程或采取一些激烈的恢复操作:

  

在忽略SIGBUS未生成的kill()sigqueue()raise()SIG_IGN信号后,流程的行为未定义, (sig)longjmp或{{1}}。

("忽略"在上下文中意味着"如果内核尝试在操作设置为{{1}}时同步生成其中一个信号。)

  

在正常从信号捕获函数返回的信号捕获函数中,进程的行为是未定义的,该函数不是由kill(),sigqueue()或raise()生成的SIGBUS,SIGFPE,SIGILL或SIGSEGV信号。 / p>

("正常返回"表示"不是通过调用{{1}}"。 有效,至少就内核而言关心,放松堆栈并在其他地方恢复执行;如果你没有充分修复造成故障的损坏数据结构,你可能会遇到麻烦。它也有效正如Basile所提到的那样,要弄乱已保存的处理器状态,以便返回"通常"不会再尝试再次运行相同的错误指令;但是 倾向于涉及手动解释机器指令和其他黑魔法。)

  

如果在阻塞时生成任何SIGFPE,SIGILL,SIGSEGV或SIGBUS信号,则结果是未定义的,除非信号是由另一个进程的动作或其中一个函数kill()生成的, pthread_kill(),raise()或sigqueue()。

(我不确定为什么这个措辞与其他两个措辞略有不同;可能只是因为撰写specific documentation for sigprocmask的人没有与编写{general documentation for signal actions的人协调3}}。)


0 Dima标记了他们的问题" Linux",但无论如何我会提出这个警告,为了未来的读者的利益:我在这里写的所有东西都应该被假定为仅将应用于符合POSIX标准的操作系统;对于第一个订单,这意味着"您可能遇到的所有操作系统,除了Windows。"例外非常重要。 Windows对线程和进程之间的关系有一个比POSIX更为不同的概念,以及完全不同(优越!)基本机制,用于报告CPU生成的错误程序异常。 Windows上的信号由C库模拟,可能 not 的行为与我描述的一样 1 可能实际上是pthread_kill 2 请阅读此整个系列博客文章 3 具体来说,是The Open Group Base Specifications Issue 7, 2013 edition的在线副本,同时也是"同时" 2013版IEEE标准1003.1,POSIX 4 不是很多,但不是没有;在" Signal Actions"中有一个列表文档,但没有片段ID允许我指向你。

答案 2 :(得分:0)

  

我有接收信号SIGSEGV的功能,但不做任何事情,   这是否意味着忽略了信号?

从技术上讲,它并没有被忽视。你定义了信号处理程序,虽然函数没有做任何事情,但它确实处理了信号。 请注意,就信号而言,IGNORE意味着内核不处理信号,也就是说,它不采取任何操作。

每个信号都有默认动作。它是SEGV的coredump(以核心终止)并终止SEGKILL等......

用户可以使用signal()或sigaction()API更改默认操作,操作可以设置为以下之一:

  1. 执行默认操作
  2. 忽略信号
  3. 使用信号处理程序捕获信号
  4. 所以在你的情况下,它是第三个。如果你使用了第二个动作,我会说忽略信号。

      

    信号是否传递给默认实现?

    没有

    请阅读http://man7.org/linux/man-pages/man7/signal.7.html了解更多信息。