2010-03-25 127 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