如何分配完整的内存页面

时间:2017-04-11 17:20:09

标签: c++ c linux memory-management x86-64

在C或C ++中,在Linux上,我想在系统内存页面大小的整页中分配堆内存。

(目的是我希望增加有害缓冲区溢出导致分段错误的可能性。)

当我使用C ++数组new(pointer = new char[size])分配内存时,其中size是sysconf(_SC_PAGESIZE)的倍数,那么分配的内存的(虚拟)地址通常不会是{{的倍数1}},表示我有一个较大块的子集,通过写入指针[size]和稍微超出(强制缓冲区溢出)这一事实证实通常不会导致分段错误。

我的问题是,我可以以某种方式影响内存分配,以便为我提供完整的内存页面。

我感兴趣的处理器架构是x86_64 aka amd64。操作系统是最新的Ubuntu,或者是稳定的CentOS Linux(7.3),后者附带内核3.10和gcc-4.8。

我不在乎解决方案是使用C还是C ++,因此我要求在此问题中保留C标记。

1 个答案:

答案 0 :(得分:3)

1)只需从pointer = new char[size]切换到pointer = aligned_alloc(sysconf(_SC_PAGESIZE), size),就会导致正确的页面对齐和(到目前为止,小型测试程序)超出分配范围时一致生成分段错误。正如@JohnBollinger在对该问题的第一次评论中指出的那样,单独分配方法无法保证分段错误的产生。这可以用2)修复:

2)函数mprotect的Linux手册页包含一个限制访问内存页面的完整示例。该示例还为SIGSEGV提供了一个信号处理程序,我对此并不感兴趣,默认操作(abort)对我来说已经足够了。手册页的示例部分如下。请注意,将mprotect应用于与mmap无关的内存区域是POSIX未涵盖的特定于Linux的扩展。

  

实施例

     

下面的程序分配四页内存,第三项   这些页面只读,然后执行循环遍历   向上通过分配的区域修改字节。

     

运行程序时我们可能会看到的一个例子是   以下内容:

       $ ./a.out
       Start of region:        0x804c000
       Got SIGSEGV at address: 0x804e000
     

节目来源

   #include <unistd.h>
   #include <signal.h>
   #include <stdio.h>
   #include <malloc.h>
   #include <stdlib.h>
   #include <errno.h>
   #include <sys/mman.h>

   #define handle_error(msg) \
       do { perror(msg); exit(EXIT_FAILURE); } while (0)

   static char *buffer;

   static void
   handler(int sig, siginfo_t *si, void *unused)
   {
       printf("Got SIGSEGV at address: 0x%lx\n",
               (long) si->si_addr);
       exit(EXIT_FAILURE);
   }

   int
   main(int argc, char *argv[])
   {
       char *p;
       int pagesize;
       struct sigaction sa;

       sa.sa_flags = SA_SIGINFO;
       sigemptyset(&sa.sa_mask);
       sa.sa_sigaction = handler;
       if (sigaction(SIGSEGV, &sa, NULL) == -1)
           handle_error("sigaction");

       pagesize = sysconf(_SC_PAGE_SIZE);
       if (pagesize == -1)
           handle_error("sysconf");

       /* Allocate a buffer aligned on a page boundary;
          initial protection is PROT_READ | PROT_WRITE */

       buffer = memalign(pagesize, 4 * pagesize);
       if (buffer == NULL)
           handle_error("memalign");

       printf("Start of region:        0x%lx\n", (long) buffer);

       if (mprotect(buffer + pagesize * 2, pagesize,
                   PROT_READ) == -1)
           handle_error("mprotect");

       for (p = buffer ; ; )
           *(p++) = 'a';

       printf("Loop completed\n");     /* Should never happen */
       exit(EXIT_SUCCESS);
   }

前一句话的归属:

  

此页面是Linux man-pages项目4.04版的一部分   项目描述,有关报告错误的信息,以及   该页面的最新版本可在http://www.kernel.org/doc/man-pages/找到。