2010-03-25 129 views
5

我正在编写一个应该在FreeBSD 8.0和Linux上运行的高负载守护进程。守护进程的主要目的是传递由其标识符请求的文件。标识符通过对db的请求转换为本地文件名/文件大小。然后我使用顺序mmap()调用来传递文件块send()检查mmap的地址是否正确

但是有时候db中的文件大小和文件系统上的文件大小不匹配(在db中重新实现<大小)。在这种情况下,我发送了所有真实的数据块,并且在下一个数据块被映射时 - mmap不返回错误,只是通常的地址(我也检查过errno变量,它在mmap之后等于零)。当守护程序尝试发送此块时,它会得到分段错误。 (此行为在FreeBSD 8.0 amd64上保证发布)

我之前使用安全检查打开以确保调用stat()的大小。然而现实生活中,我发现segfault仍然可以在罕见的情况下提出。

所以,我的问题是有没有办法检查指针是否可以在解除引用之前访问?当我在gdb中打开core时,gdb说给定的地址是无界的。 也许有人可以提出另一种解决方案。

#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <time.h> 
#include <unistd.h> 

#define FILENAME  "./datafile" 

int main() 
{ 
    unsigned long i, j; 

    srand(time(NULL)); 
    unsigned long pagesize = sysconf(_SC_PAGESIZE); 

    unsigned long basesize = 4 * pagesize; 
    unsigned long cropsize = 2 * pagesize; 

    // create 4*pagesize sized file 
    int f = creat(FILENAME, 0644); 
    for (i = 0; i < basesize; i++) { 
     unsigned char c = (unsigned char)rand(); 
     if (write(f, &c, 1) < 1) { perror("write"); break; } 
    } 
    close(f); 

    f = open(FILENAME, O_RDONLY); 

    // walk trough file 
    unsigned char xor = 0; 
    unsigned long offset = 0; 
    for (j = 0; j < 4; j++) { 
     // trunc file to 2*pagesize 
     if (j == 2) truncate(FILENAME, cropsize); 

     char *data = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE, f, offset); 
     if (data == MAP_FAILED) { perror("mmap"); break; } 
     printf("mmap: %[email protected]%lu for %i\n", pagesize, offset, f); 

     for (i = 0; i < pagesize; i++) xor ^= data[i]; 

     offset += pagesize; 
    } 

    close(f); 

    return 0; 
} 

回答

2

当然我不能从这里证明这一点,但我强烈怀疑,你只需要在你的代码中的簿记错误。如果您调用mmap并传入大小,并且成功,则不应该获得SIGSEGV。

我建议您将valgrind应用于您的调查。

在许多Linux系统上,/ proc/PID/maps会告诉你哪些区域映射了什么访问权限。

+0

我已经把代码示例说明了头文章中的问题。此代码模拟文件的创建,然后在处理mmap时调整其大小。 在Linux系统上,第三步我遇到了总线错误,在FreeBSD上有SegFault。 – reddot 2010-03-26 12:55:52