C SIGSEGV Handler& MPROTECT

时间:2010-04-24 19:10:29

标签: signals handler sigsegv mprotect

我正在构建一个程序,它使用mprotect()来限制一块内存访问。当请求内存时,抛出SIGSEGV,我使用signal()调用来监听。

一旦检测到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);
}

另外,有没有办法确定当前分配了一块内存(PROT_NONE,PROT_READ等等)的mprotect()级别?

3 个答案:

答案 0 :(得分:6)

您必须使用sigactionSA_SIGINFO代替signal来建立您的处理程序,然后您将在siginfo_t中收到有用信息的回复,包括{ {1}}。

si_addr(2)中所述,

si_addr将包含地址。至于长度,除非你愿意解析说明,否则你运气不好。你能做的最好就是对sigaction中报告的页面采取行动,然后如果这还不够,你很快就会得到另一个信号。至少,这就是我们在ObjectStore中做事的方式。

答案 1 :(得分:1)

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

但请注意,调用mprotect仅在Linux中是信号安全的,其他POSIX系统可能不支持此功能。

我担心在Linux中获取内存保护位的唯一方法是读入/proc/$pid/meminfo

旁注(仅限Linux):如果您担心内存消耗并打算逐个启用较大映射的页面,那么我建议使用mmap和{{1}创建映射在这种情况下,您将获得映射到零填充的写时复制页面,这将在第一次写入时分配物理RAM。 MAP_NORESERVE指示内核不要使用交换空间来备份内存,从而允许您分配最多64TB的虚拟地址空间。唯一的缺点是,如果你的内存耗尽,可能会发生可怕的事情(oom-killer)。

答案 2 :(得分:1)

第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的手册页,以获取处理程序可以提取的更多有趣数据。