映射两个连续的页面

时间:2009-02-27 16:35:36

标签: c unit-testing unix memory-mapped-files

我正在为我的UTF8操作库编写单元测试,如果函数进入缓冲区溢出,我希望我的测试能够进行段错误。所以我想出了在内存中将两个页面相邻的mmap,第一个用PROT_READ | PROT_WRITE,第二个是PROT_NONE。这样,如果发生任何溢出,则保证段错误。这是一个例子:


void *addr1, *addr2; /* these are the pages; mmap call left out for simplicity */
char *p = (char *) (addr1 + getpagesize() - 8);

utf8_encode(aUtf8String, p, 8); // this shouldn't segfault

问题是,当我映射第二页时,我的程序会出现段错误。这是一个重现问题的示例程序(GNU / Linux):


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>

void checkMap(void *p) 
{ 
    if(p == MAP_FAILED) {
        printf("error running mmap: %s\n", strerror(errno));
        exit(1);
    }   
}

int main(void)
{
    void *addr1, *addr2;
    size_t pagesize;

    pagesize = getpagesize();
    checkMap(addr1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
    checkMap(addr2 = mmap(addr1 + pagesize, pagesize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));  /* segfaults */
    munmap(addr1, pagesize);
    munmap(addr2, pagesize);

    return 0;
}

有趣的是,第一个mmap()之前的printf()语句会导致程序成功运行。有谁知道为什么mmap是segfaulting?如果使用mmap()无法实现我的目标,那么是否有人对如何测试代码进行缓冲区溢出有任何其他建议?

2 个答案:

答案 0 :(得分:3)

您可以调用mprotect()来更改mmap()映射的内存上的保护标志。这可能比尝试mmap()具有不同保护的两个相邻页面更好的解决方案,因为这似乎是导致您出现问题的原因。

(Linux允许您在任何页面上调用mprotect(),但POSIX仅允许已由mmap()分配的页面。)

这是Electric Fence用于捕获缓冲区溢出的技巧之一。

答案 1 :(得分:0)

这与你的问题并不完全相关(除非你的最终目标确实是让你的测试工作),但是,恕我直言,依靠这种故障处理可能会产生误导(最值得注意的是,如果你的目标是多个平台,如果由于某些未指明的行为而未触发seg-fault,则测试应该失败。

也许一种不同的方法对你来说更有意义,例如,简单地分配一个比必要更大的缓冲区,在它的末尾放置一个标记,并检查它是否被覆盖了?

正如其他人所提到的,如果你愿意建立一个更复杂的测试环境,电篱笆,valgrind或其他工具可能在他们的分析中更精细。