为什么该程序在用户的信号处理程序之后没有终止

时间:2019-11-16 12:15:36

标签: c concurrency signals

在调试下一个代码段时,调试器使用 Column 'epro_id' cannot be null at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1340) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025) ~[mysql-connector-java-8.0.17.jar:8.0.17] 返回到x=10/x行,仍然得到x=5

SIGFPE
  • 这里发生了什么?
  • 处理程序实际返回到哪一点?

2 个答案:

答案 0 :(得分:1)

如前所述,这在技术上是不确定的行为。

发生的情况是SIGFPE重复出现。如果您从信号处理程序中添加一条打印语句,您将看到:

#include <signal.h>

volatile sig_atomic_t x = 0;

void sigfpe_handler(int signum) {
    x = 5;
    write(2, "Received SIGFPE\n", sizeof "Received SIGFPE\n" - 1 );
}

int main() {
    signal(SIGFPE, sigfpe_handler);
    x = 10 / x;
    return 0;
}

这是因为,当发生信号时,控件将转移到信号处理程序,并且一旦返回,“ main”代码就会从指令(而不是语句)执行被中断(通过信号)。在这种情况下,它将继续进行除法并发生SIGFPE,并且循环继续进行。

您可以看到确切的指令,它从gdb重复:

Program received signal SIGFPE, Arithmetic exception.
0x00000000004005a6 in main ()
(gdb) disass
Dump of assembler code for function main:
   0x000000000040057c <+0>:     push   %rbp
   0x000000000040057d <+1>:     mov    %rsp,%rbp
   0x0000000000400580 <+4>:     sub    $0x10,%rsp
   0x0000000000400584 <+8>:     mov    $0x40054c,%esi
   0x0000000000400589 <+13>:    mov    $0x8,%edi
   0x000000000040058e <+18>:    callq  0x400430 <signal@plt>
   0x0000000000400593 <+23>:    mov    0x20042b(%rip),%edx        # 0x6009c4 <x>
   0x0000000000400599 <+29>:    mov    %edx,-0x4(%rbp)
   0x000000000040059c <+32>:    mov    $0xa,%eax
   0x00000000004005a1 <+37>:    mov    %eax,%edx
   0x00000000004005a3 <+39>:    sar    $0x1f,%edx
=> 0x00000000004005a6 <+42>:    idivl  -0x4(%rbp)
   0x00000000004005a9 <+45>:    mov    %eax,0x200415(%rip)        # 0x6009c4 <x>
   0x00000000004005af <+51>:    mov    $0x0,%eax

(gdb) p $rbp
$8 = (void *) 0x7fffffffada0
(gdb) p *(int*)$rbp
$9 = 0

如果您注意到,x的值已经被加载到寄存器中,这就是它的用途。这就是为什么更改x并没有达到您期望的效果。

您可以执行“跳转”,然后跳过导致代码的FPE:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <setjmp.h>

sigjmp_buf jbuf;

volatile sig_atomic_t x = 0;

void sigfpe_handler(int signum) {
    x = 5;
    write(2, "Received SIGFPE\n", sizeof "Received SIGFPE\n" - 1 );
    siglongjmp(jbuf, 1);
}

int main() {
    signal(SIGFPE, sigfpe_handler);
    if (sigsetjmp(jbuf, 0) == 0)
        x = 10 / x;
    else
        printf("Returned from siglongjmp\n");
    return 0;
}

请注意有关sigsetjmp/siglongjmp的说明。

答案 1 :(得分:0)

您为 $(".t1").tooltip({ content: "<div><div class='tit'>Some super titlet</div> <div class='x'>x</div><div class='con'>Some content super super long</div></h1>", disabled: true, width:550, tooltipClass: "myClass", open: function (event, ui) { var $element = $(event.target); ui.tooltip.each(function () { $("div.x",this).click(function () { $element.tooltip('close'); }); }); }, }).on('mouseout focusout', function(event) { event.stopImmediatePropagation(); }); $(".tooltip").click(function() { $(this) .tooltip("open") }); 安装了一个信号处理程序,该信号处理程序通常会返回,然后执行一些操作使系统生成该信号。

根据POSIX规范:

  

进程的行为通常是从不是由kill(),sigqueue()或raise()生成的SIGBUS,SIGFPE,SIGILL或SIGSEGV信号的信号捕获函数返回后,不确定其行为。 / p>

C标准中有类似的措辞。因此,接下来发生的事情是您无法控制的,因为它是未定义的行为。您的程序可能会继续运行,可能会进入无限循环,等等。

此外,如果您希望在处理程序中可靠且可移植地看到对处理程序中所做的更改,则SIGFPE变量的类型必须为x(假设该处理程序不会导致未定义的行为,例如在此示例中所做的)。 C11无锁原子类型也可以。