Tôi đang viết một trình tiện ích được tải cao nên chạy trên FreeBSD 8.0 và trên Linux. Mục đích chính của daemon là chuyển các tập tin được yêu cầu bởi mã định danh của chúng. Số nhận dạng được chuyển đổi thành tên tệp/kích thước tệp cục bộ theo yêu cầu thành db. Và sau đó tôi sử dụng các lệnh gọi mmap()
tuần tự để chuyển khối tệp bằng send()
.kiểm tra xem địa chỉ mmap'ed có chính xác không
Tuy nhiên đôi khi có sự không phù hợp về kích thước tệp trong db và định cỡ tệp trên hệ thống tệp (kích thước realsize < trong db). Trong tình huống này, tôi đã gửi tất cả các khối dữ liệu thực và khi khối dữ liệu tiếp theo được ánh xạ - mmap trả về không có lỗi, chỉ là địa chỉ bình thường (tôi đã kiểm tra biến errno cũng vậy, nó bằng 0 sau mmap). Và khi daemon cố gắng gửi khối này, nó sẽ bị Lỗi phân đoạn. (Hành vi này được bảo hành phát hành trên FreeBSD 8.0 amd64)
Tôi đã sử dụng séc an toàn trước khi mở để đảm bảo kích thước với cuộc gọi stat()
. Tuy nhiên, cuộc sống thực sự cho tôi thấy rằng sự phân biệt vẫn có thể được nâng lên trong những điều hiếm hoi.
Vì vậy, câu hỏi của tôi là có cách để kiểm tra xem con trỏ có thể truy cập được trước khi bỏ qua nó không? Khi tôi đã mở lõi trong gdb, gdb nói rằng địa chỉ đã cho là bị ràng buộc. Có lẽ có một giải pháp khác mà ai đó có thể đề xuất.
#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;
}
Tôi đã đặt mẫu mã minh họa sự cố trong bài đăng đầu. Mã này mô phỏng việc tạo tệp và sau đó thay đổi kích thước tệp trong khi nó đã được tiến hành với mmap. Trên hệ thống Linux, tôi gặp Lỗi Bus trên bước thứ ba, trên FreeBSD có SegFault. – reddot