Можем ли мы сбросить sigsetjmp для возврата «0» снова (Сброс sigsetjmp)? - PullRequest
1 голос
/ 08 августа 2011

Я написал обработчик ошибок сегментации, используя 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 Ответ

7 голосов
/ 08 августа 2011

Вы неправильно поняли, как работает [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 немного неудачно, но на самом деле глючит .Вам не нужен /dev/zero на большинстве современных платформ, вы можете просто использовать MAP_ANON (на некоторых платформах это пишется MAP_ANONYMOUS) и аргумент -1 fd.И вы должны использовать getpagesize, а затем запрашивать целое количество страниц.

...