私は、FreeBSD8.0とLinuxでも実行されるべき高負荷のデーモンを書いています。デーモンの主な目的は、識別子によって要求されたファイルを渡すことです。識別子は、dbへの要求を介してローカルファイル名/ファイルサイズに変換されます。次に、順次mmap()
呼び出しを使用して、。を使用してファイルブロックを渡しますsend()
。
ただし、dbのファイルサイズとファイルシステムのファイルサイズが一致しない場合があります(realsize <dbのサイズ)。この状況では、すべての実際のデータブロックを送信し、次のデータブロックがマップされると、mmapはエラーを返さず、通常のアドレスだけを返します(errno変数もチェックしました。mmap後はゼロになります)。そして、デーモンがこのブロックを送信しようとすると、セグメンテーション違反が発生します。(この動作は、FreeBSD 8.0 amd64で確実に発行されます)
stat()
私は、電話でサイズを確認するために、開く前に安全なチェックを使用していました。ただし、実際の生活では、まれな状況でセグメンテーション違反が発生する可能性があることがわかります。
だから、私の質問は、ポインターを逆参照する前に、ポインターがアクセス可能かどうかを確認する方法がありますか?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: %lu@%lu for %i\n", pagesize, offset, f);
for (i = 0; i < pagesize; i++) xor ^= data[i];
offset += pagesize;
}
close(f);
return 0;
}