2010-03-25 5 views
5

Я пишу высоконагруженный демон, который должен запускаться на FreeBSD 8.0 и на Linux. Основная цель демона - передать файлы, запрашиваемые их идентификатором. Идентификатор преобразуется в локальное имя файла/размер файла по запросу db. И затем я использую последовательные вызовы mmap() для передачи файлов с send().проверить, правильно ли установлен адрес mmap'a

Однако иногда возникают несоответствия файлов в db и размер файла в файловой системе (realsize < size in db). В этой ситуации я отправил все реальные блоки данных и когда следующий блок данных отображен - mmap не возвращает никаких ошибок, просто обычный адрес (я также проверил переменную errno, она равна нулю после mmap). И когда демон пытается отправить этот блок, он получает Segmentation Fault. (Такое поведение гарантировано выдается на FreeBSD 8.0 amd64)

Я использовал безопасную проверку перед открытием, чтобы обеспечить размер с помощью stat(). Однако реальная жизнь показывает мне, что segfault все еще может быть поднят в редких ситуациях.

Итак, у меня вопрос, есть ли способ проверить, доступен ли указатель до разыменования его? Когда я открыл ядро ​​в gdb, 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