gpt4 book ai didi

linux - Unix 表示怀疑 - 对以下程序的执行

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:15:02 25 4
gpt4 key购买 nike

我有下面这个程序

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

int x = 1;

void ouch(int sig) {
printf("OUCH! dividing by zero!\n");
x = 0;
}

void fpe(int sig) {
printf("FPE! I got a signal: %d\n",sig);
psignal(sig, "psignal");
x = 1;
}

int main(void) {
(void) signal(SIGINT, ouch);
(void) signal(SIGFPE, fpe);

while(1)
{
printf("Hello World: %d\n",1/x);
sleep(1);
}
}

问题:在执行该程序时 - 当我从终端向程序提供 SIGINT 信号时 - ""OUCH!除以零! "是输出 - 正如预期的那样。下一条消息是 “FPE!我收到一个信号:8 psignal:浮点异常“。这条信息一直在继续——没有停止。我怀疑在调用 fpe 信号处理程序后,我将 x 设置为 1。因此,我希望 Hello World 应该显示在输出中。

下面是我得到的输出的抄本:

Hello World: 1
Hello World: 1
^COUCH! dividing by zero!
FPE! I got a signal: 8
psignal: Floating point exception
FPE! I got a signal: 8
psignal: Floating point exception
FPE! I got a signal: 8
psignal: Floating point exception
^COUCH! dividing by zero!

.
.
.
.

最佳答案

当进入信号处理程序时,程序计数器(指向当前正在执行的指令的 CPU 寄存器)被保存在被零除发生的位置。忽略信号会将 PC 恢复到完全相同的位置,在该位置再次触发信号(一次又一次)。

'x' 的值或波动率此时无关紧要 - 零已传输到 CPU 寄存器中以准备执行除法。

man 2 signal注意到:

According to POSIX, the behaviour of a process is undefined after it ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by the kill(2) or the raise(3) functions. Integer division by zero has undefined result. On some architectures it will generate a SIGFPE signal. (Also dividing the most negative integer by -1 may generate SIGFPE.) Ignoring this signal might lead to an endless loop.

如果您使用调试标志进行编译,我们可以在 gdb 中看到这一点:

simon@diablo:~$ gcc -g -o sigtest sigtest.c simon@diablo:~$ gdb sigtestGNU gdb 6.8-debianCopyright (C) 2008 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i486-linux-gnu"...

默认情况下,gdb 不会将 SIGINT 传递给进程 - 更改它以便它看到第一个信号:

(gdb) handle SIGINT passSIGINT is used by the debugger.Are you sure you want to change it? (y or n) ySignal        Stop  Print   Pass to program DescriptionSIGINT        Yes   Yes Yes     Interrupt

我们出发了:

(gdb) runStarting program: /home/simon/sigtest x = 1Hello World: 1

现在让我们打断它:

^CProgram received signal SIGINT, Interrupt.0xb767e17b in nanosleep () from /lib/libc.so.6

然后再往前走:

(gdb) contContinuing.OUCH!  dividing by zero!x = 0Program received signal SIGFPE, Arithmetic exception.0x0804853a in main () at sigtest.c:3030              printf("Hello World: %d\n",1/x);

检查'x'的值,然后继续:

(gdb) print x$1 = 0(gdb) contContinuing.FPE!  I got a signal: 8psignal: Floating point exceptionProgram received signal SIGFPE, Arithmetic exception.0x0804853a in main () at sigtest.c:3030              printf("Hello World: %d\n",1/x);(gdb) print x$2 = 1

x 显然现在是 1,我们仍然得到除以零 - 发生了什么事?让我们检查底层汇编器:

(gdb) disassemble Dump of assembler code for function main:0x080484ca :    lea    0x4(%esp),%ecx0x080484ce :    and    $0xfffffff0,%esp...0x08048533 :  mov    %eax,%ecx0x08048535 :  mov    %edx,%eax0x08048537 :  sar    $0x1f,%edx0x0804853a :   idiv   %ecx           <<-- address FPE occurred at0x0804853c :  mov    %eax,0x4(%esp)0x08048540 :  movl   $0x8048653,(%esp)0x08048547 :  call   0x8048384 0x0804854c :  jmp    0x8048503 End of assembler dump.

Google 搜索后告诉我们 IDIV将 EAX 寄存器中的值除以源操作数 (ECX)。你大概能猜到寄存器内容:

(gdb) info registers eax            0x1  1ecx            0x0  0...

关于linux - Unix 表示怀疑 - 对以下程序的执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4091696/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com