4

我正在构建一个程序,它使用 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);
}

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

4

3 回答 3

6

您必须使用sigactionwithSA_SIGINFO而不是signal来建立您的处理程序,然后您将被回调,并在 a 中包含有用的信息siginfo_t,包括si_addr.

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

于 2010-04-24T19:13:20.470 回答
1

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

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

恐怕在Linux中获得内存保护位的唯一方法是读入/proc/$pid/meminfo

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

于 2012-09-27T19:12:21.097 回答
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

于 2016-09-29T04:03:36.243 回答