教訓
アーカイブファイルを読み出す際、アーカイブファイルサイズ分のメモリを確保するのは馬鹿げている。何も考えずに open(2) -> fstat(2) -> malloc(3) -> read(2) しちゃいけませんって事で…。いきなり 4GB 位のファイルを食わせると泣けます…。
fread(3) や fgetc(3) を使うのはエラー処理とか面倒なので、こういう時には mmap(2)。
修正前:
#include#include #include #include #include int kma(void) { struct stat sb; char *top = NULL, *p; int fd = -1; int rv = 1; fd = open("kma.arc", O_RDONLY); if (fd < 0) { perror("open"); goto failure; } if (fstat(fd, &sb) < 0) { perror("fstat"); goto file_close; } top = malloc(sb.st_size); if (top == NULL) { fprintf(stderr, "malloc failure (size = %d)\n", sb.st_size); goto file_close; } if (read(fd, p, sb.st_size) != sb.st_size) { perror("read"); goto memory_free; } p = top; ... rv = 0; memory_free: if (top != NULL) free(top); file_close: if (fd >= 0) close(fd); failure: return rv; }
修正後:
#include#include #include #include #include #include #include #include int kma(void) { struct stat sb; char *top = MAP_FAILURE, *p; int fd = -1; int rv = 1; fd = open("kma.arc", O_RDONLY); if (fd < 0) { perror("open"); goto failure; } if (fstat(fd, &sb) < 0) { perror("fstat"); goto file_close; } top = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (top == MAP_FAILURE) { perror("mmap"); goto file_close; } p = top; ... rv = 0; memory_free: if (top != MAP_FAILURE) munmap(top, sb.st_size); file_close: if (fd >= 0) close(fd); failure: return rv; }