我们可以重置sigsetjmp再次返回“0”(重置sigsetjmp)吗?

时间:2011-08-08 16:41:37

标签: c linux signals setjmp

我使用sigsetjmp和siglongjmp编写了一个分段错误处理程序。一旦它进入信号处理程序,我调用siglongjmp,以便跳过错误的指令。

问题是,我再次想要导致SIGSEGV并转到相同的处理程序,但现在sigsetjmp将返回1.

如何重置sigsetjmp?

这是我的代码:

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>

sigjmp_buf env, env1;

void SIGSEGV_handler(int signal)
{
  printf("Segmentation fault caught\n");
  siglongjmp(env, 1);
}

int main()
{
 void * allocation;
 size_t size;
 static int devZerofd = -1;
 struct sigaction sa, sa1;

 sa.sa_handler=(void*)SIGSEGV_handler;
 sigaction(SIGSEGV, &sa, NULL);

 if ( devZerofd == -1 ) {
     devZerofd = open("/dev/zero", O_RDWR);
     if ( devZerofd < 0 )
         perror("open() on /dev/zero failed");
  }

 allocation = (caddr_t) mmap(0, 5000, PROT_READ|PROT_NONE, MAP_PRIVATE, devZerofd,  0);

 if ( allocation == (caddr_t)-1 )
    fprintf(stderr, "mmap() failed ");

 if ( mprotect((caddr_t)allocation, 5000, PROT_NONE) < 0 )
     fprintf(stderr, "mprotect failed");
 else
     printf("mprotect done: memory allocated at address %u\n",allocation);

 if(sigsetjmp(env, 1)==0) {
      printf("Causing SIGSEGV: 1\n");
      strcpy(allocation,"Hello, how are you");
  }

  /****** This can't be done again as sigsetjmp won't return 0*****/
  /*

  if(sigsetjmp(env, 1)==0) {
      printf("Causing SIGSEGV: 1\n");
      strcpy(allocation,"Hello, how are you");
  }
   */
 }

1 个答案:

答案 0 :(得分:7)

您误解了[sig]setjmp的工作原理。如果你取消注释你认为不起作用的代码,编译它并运行它,你会发现它确实有效。

setjmp无法通过调用longjmp 返回零。如果您第二次致电setjmp,即使使用相同的jmp_buf(就像您在此处一样),它也会再次返回零。

顺便提一下,你有一个错误:你没有正确设置sigaction参数结构。你应该这样做:

struct sigaction sa;

sa.sa_handler = SIGSEGV_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGSEGV, &sa, 0);

使用mmap有点不合适,但实际上并非 buggy 。在大多数当前平台上,您不需要/dev/zero,您可以使用MAP_ANON(某些平台拼写为MAP_ANONYMOUS)和-1 fd参数。你应该使用getpagesize,然后要求提供一整页页面。