我正在为我的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()无法实现我的目标,那么是否有人对如何测试代码进行缓冲区溢出有任何其他建议?
答案 0 :(得分:3)
您可以调用mprotect()来更改mmap()
映射的内存上的保护标志。这可能比尝试mmap()
具有不同保护的两个相邻页面更好的解决方案,因为这似乎是导致您出现问题的原因。
(Linux允许您在任何页面上调用mprotect()
,但POSIX仅允许已由mmap()
分配的页面。)
这是Electric Fence用于捕获缓冲区溢出的技巧之一。
答案 1 :(得分:0)
这与你的问题并不完全相关(除非你的最终目标确实是让你的测试工作),但是,恕我直言,依靠这种故障处理可能会产生误导(最值得注意的是,如果你的目标是多个平台,如果由于某些未指明的行为而未触发seg-fault,则测试应该失败。
也许一种不同的方法对你来说更有意义,例如,简单地分配一个比必要更大的缓冲区,在它的末尾放置一个标记,并检查它是否被覆盖了?
正如其他人所提到的,如果你愿意建立一个更复杂的测试环境,电篱笆,valgrind或其他工具可能在他们的分析中更精细。