2010-04-24 23 views
4

我正在構建一個使用mprotect()來限制內存訪問的程序。當請求存儲器時,將使用signal()調用偵聽SIGSEGV。C SIGSEGV Handler&Mprotect

一旦檢測到SIGSEGV,我需要以某種方式訪問​​指向請求的內存的指針(拋出錯誤)和請求的段的大小。這可能嗎?

void fifoSigHandler(){ 

    // Needs to only remove protection from requested block of virtual memory 
    mprotect(fifoVm,(size_t)fifoVm_size,PROT_WRITE); 
    printf("Caught Seg Fault"); 
} 

void fifo_init(void* vm, int vm_size, int n_frames, int page_size) 
{ 
    fifoVm = vm; 
    fifoVm_size = vm_size; 
    fifoFrames = n_frames; 
    fifoPageSize = page_size; 

    mprotect(fifoVm,(size_t)fifoVm_size,PROT_NONE); 

    signal(SIGSEGV, fifoSigHandler); 
} 

此外,有一種方法,以確定的mprotect的水平()的內存塊當前被分配(PROT_NONE,PROT_READ,等等。)?

回答

5

你必須使用sigactionSA_SIGINFO而不是signal建立你的處理程序,然後你會得到被召回的有用信息的siginfo_t,包括si_addr

si_addr,如在sigaction(2)中所述,將包含該地址。至於長度,好吧,除非你願意解析指令,否則你運氣不佳。你可以做的最好的做法是在si_addr報告的頁面採取行動,然後如果這還不夠,你會很快得到另一個信號。至少,這就是我們在ObjectStore中做的事情。

+2

我們如何參考這些有用的信息?特別是指向所請求的內存的指針和大小 – pws5068 2010-04-24 19:15:32

1

您正在尋找libsigsegv http://libsigsegv.sourceforge.net/

但要注意,調用mprotect只是信號安全在Linux中,其他POSIX系統可能不支持此功能。

恐怕在Linux中,只有這樣才能獲得內存保護位是/proc/$pid/meminfo

閱讀在一個側面說明(僅限Linux):如果你擔心內存消耗和打算啓用的頁面然後我建議使用mmapMAP_NORESERVE來創建映射,在這種情況下,您將獲得映射到零填充的寫時複製頁面,該頁面將在第一次寫入時分配物理RAM。 MAP_NORESERVE指示內核不要使用交換空間備份內存,以便分配最多64TB的虛擬地址空間。唯一的缺點是,如果你的記憶力耗盡,恐怖的事情就會發生(兇手)。

0

步驟1:初始化一個sigaction

struct sigaction act; 
memset(&act, 0, sizeof(struct sigaction)); 
sigemptyset(&act.sa_mask); 
act.sa_sigaction = handler; 
act.sa_flags = SA_SIGINFO | SA_ONSTACK; 

步驟2:使此sigaction手柄SIGSEGV

sigaction(SIGSEGV, &act, NULL); 

(可選)步驟3:使處理其他記憶信號:

sigaction(SIGBUS, &act, NULL); 
sigaction(SIGTRAP, &act, NULL); 

加入錯誤處理必要

步驟4:定義處理函數:

void handler(int signal, siginfo_t* siginfo, void* uap) { 
    printf("Attempt to access memory at address %p\n", 
      siginfo->si_addr); 
    #ifdef LINUX_64BIT 
    printf("Instruction pointer: %p\n", 
      (((ucontext_t*)uap)->uc_mcontext.gregs[16])); 
    #elif LINUX_32BIT 
    printf("Instruction pointer: %p\n", 
      (((ucontext_t*)uap)->uc_mcontext.gregs[14])); 
    #endif 
} 

您可以參考手冊頁ucontext_tsiginfo_t更有趣的數據處理程序可以提取。