我正在編寫一個應該在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;
}
我已經把代碼示例說明了頭文章中的問題。此代碼模擬文件的創建,然後在處理mmap時調整其大小。 在Linux系統上,第三步我遇到了總線錯誤,在FreeBSD上有SegFault。 – reddot 2010-03-26 12:55:52