【问题标题】:Segmentation fault in sigaction signal handlersigaction 信号处理程序中的分段错误
【发布时间】:2013-09-04 06:02:04
【问题描述】:

在下面的代码中,如果我将 old_act 声明为全局变量,那么程序可以正常工作。如果在 main 中声明:

  1. 如果使用 SA_RESTART,它工作正常
  2. 如果不使用 SA_RESTART,则会导致分段错误。

谁能帮我理解发生了什么。

void sighandler(int signum)
{
        printf("Caught signal:%d pressed ctrl+c!!\n",signum);
}

int main()
{
        struct sigaction act_h;
        struct sigaction old_act;
        act_h.sa_handler = sighandler;
//      act_h.sa_flags = SA_RESTART;

       sigaction(SIGINT,&act_h,&old_act);

        printf("This is an infinite loop\n");
        int remain=sleep(10);
        printf("remaining time in sec : %d\n",remain);
        printf("Before second sleep\n");
        sleep(10);
        printf("This is an infinite loop\n");
        return 0;
}

从 gdb 看来,某些函数调用发生在非法位置,但不确定:

This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/diwakar/Documents/my_C_codes/L2IT/SigHandling/a.out...done.
[New LWP 5661]

warning: Can't read pathname for load map: Input/output error.
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0xb77c1938 in ?? ()
(gdb) 


(gdb) bt
#0  0xb77c1938 in ?? ()
Cannot access memory at address 0xe


(gdb) run
Starting program: /home/diwakar/Documents/my_C_codes/L2IT/SigHandling/a.out 
This is an infinite loop
^C
Program received signal SIGINT, Interrupt.
0xb7fdd424 in __kernel_vsyscall ()
(gdb) bt
#0  0xb7fdd424 in __kernel_vsyscall ()
#1  0xb7ed2f00 in nanosleep () from /lib/i386-linux-gnu/libc.so.6
#2  0xb7ed2d1f in sleep () from /lib/i386-linux-gnu/libc.so.6
#3  0x08048502 in main () at signal.c:33
(gdb) disassemble
Dump of assembler code for function __kernel_vsyscall:
   0xb7fdd414 <+0>: push   %ecx
   0xb7fdd415 <+1>: push   %edx
   0xb7fdd416 <+2>: push   %ebp
   0xb7fdd417 <+3>: mov    %esp,%ebp
   0xb7fdd419 <+5>: sysenter 
   0xb7fdd41b <+7>: nop
   0xb7fdd41c <+8>: nop
   0xb7fdd41d <+9>: nop
   0xb7fdd41e <+10>:    nop
   0xb7fdd41f <+11>:    nop
   0xb7fdd420 <+12>:    nop
   0xb7fdd421 <+13>:    nop
   0xb7fdd422 <+14>:    int    $0x80
=> 0xb7fdd424 <+16>:    pop    %ebp
   0xb7fdd425 <+17>:    pop    %edx
   0xb7fdd426 <+18>:    pop    %ecx
   0xb7fdd427 <+19>:    ret    
End of assembler dump.
(gdb) 

【问题讨论】:

  • valgrind 可能是调试此类内存问题的更好选择。
  • 重新编译再试一次...
  • 从内部处理程序中删除 printf 并重新编译没有帮助.. 仍然分段错误
  • @DiwakarSharma 是的,将 printf 从处理程序中移出并不会删除用于其他目的的段错误。

标签: c linux gdb segmentation-fault signals


【解决方案1】:

在分配之前尝试将act_h 的所有成员重置为零。 sa_flags 很可能有一些随机值,这使得信号动作表现不同。

int main()
{
        struct sigaction act_h;
        struct sigaction old_act;

        //reset all members
        memset(&act_h, 0, sizeof(act_h));
        act_h.sa_handler = sighandler;
        .... //continue your code;

}

【讨论】:

  • 那行得通,谢谢..!!你能解释一下由于没有设置act_h而发生了什么吗?为什么它会受到old_act声明的影响?类似于将旧动作保存到 old_act 但 act_h 有一些垃圾(如您所说的 sa_flags ),或者从 old_act 检索时引起问题...?
  • 另外,为什么它使用 SA_RESTART 设置...太多问题:)
  • @DiwakarSharma, memset() 将所有位设置为 0,即将结构的所有成员设置为 0。否则,它可能包含一些垃圾数据,sigaction() 或信号调度程序对这些数据的解释不同导致错误。
【解决方案2】:

您必须使用sigemptyset()sigfillset() 来初始化信号集。或者,在您的具体情况下:

sigemptyset(&act_h.sa_mask);

在您的情况下,请记住 C 没有“默认构造函数”之类的东西。因此,信号集和其他自动变量没有被自动初始化,很可能包含垃圾值。

另外,请注意,直接将相关结构的内存设置为零是正确初始化空信号集的不可靠方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    相关资源
    最近更新 更多