Я пишу высоконагруженный демон, который должен запускаться на 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;
}
Я разместил образец кода, который иллюстрирует проблему в главном сообщении. Этот код эмулирует создание файла, а затем изменяет его размер, пока он продолжается с помощью mmap. В системе Linux у меня ошибка шины на третьем шаге, на FreeBSD есть SegFault. – reddot