2011-08-08 102 views
1

我寫了一個分段錯誤處理程序,使用sigsetjmp和siglongjmp。一旦它進入信號處理程序,我調用siglongjmp,以便跳過錯誤的指令。我們可以重置sigsetjmp以再次返回「0」(Reset sigsetjmp)嗎?

問題是,我想再次引起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"); 
    } 
    */ 
} 

回答

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是有點不恰當的,但實際上沒有。在大多數當前平臺上,您不需要/dev/zero,您可以使用MAP_ANON(某些平臺拼寫爲MAP_ANONYMOUS)和-1 fd參數。你應該使用getpagesize,然後詢問整個頁面。

+0

setjmp從longjmp返回時返回1,對不對?所以你的意思是,如果後續調用,它再次返回0? – kingsmasher1

+0

SA_RESTART你的意思是因爲它是可中斷的功能?但它的工作原理也沒有:) – kingsmasher1

+0

或多或少,是的。請記住,每次調用'setjmp'時,如果控件第一次到達'setjmp',則返回_twice_:first;如果調用'setjmp'調用時使用了相同的'jmp_buf'調用'longjmp',則返回秒。第一個返回總是返回零。第二個返回返回'longjmp'的第二個參數,除非它是零,在這種情況下它返回一個。但是,當你再次調用setjmp時,它將設置一對新的return,並且第一個將再次返回零。 – zwol

相關問題