2012-04-20 12 views
5

Byłem ciekawy, jakie rozmiary buforów write() i read() mogłyby obsłużyć w systemie Linux/OSX/FreeBSD, więc zacząłem grać z takimi głupimi programami jak następujące:segfault na write() z buforem ~ 8MB (OSX, Linux)

#include <unistd.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <string.h> 
#include <sys/stat.h> 

int main(void) { 
    size_t s = 8*1024*1024 - 16*1024; 
    while(1) { 
     s += 1024; 
     int f = open("test.txt", O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR); 
     char mem[s]; 
     size_t written = write(f, &mem[0], s); 
     close(f); 
     printf("(%ld) %lu\n", sizeof(size_t), written); 
    } 
    return 0; 
} 

To pozwoliło mi sprawdzić, jak blisko „bariery 8MB” pozorny mogę dostać przed segfaulting. Gdzieś około znakiem 8MB, umiera mój program, oto przykładowe wyjście:

(8) 8373248 
(8) 8374272 
(8) 8375296 
(8) 8376320 
(8) 8377344 
(8) 8378368 
(8) 8379392 
(8) 8380416 
(8) 8381440 
(8) 8382464 
Segmentation fault: 11 

To samo na OSX i Linux, jednak moja FreeBSD VM jest nie tylko o wiele szybciej przy uruchomieniu tego testu, ale również mogą przejść na na wiele sposobów! Udało mi się przetestować go do 511 MB, co jest po prostu śmieszną ilością danych do napisania w jednym wywołaniu.

Co sprawia, że ​​polecenie write() wywołuje błąd segfault i jak mogę obliczyć maksymalną ilość, jaką mogę ewentualnie zapisać() w jednym wywołaniu, bez robienia czegoś tak absurdalnego, jak robię to teraz?

(Uwaga: Wszystkie trzy systemy operacyjne są 64-bitowe, OS X 10.7.3 Ubuntu 11,10 FreeBSD 9,0)

Odpowiedz

5

błędu nie jest w write(), to przepełnienia stosu. Wypróbuj to:

#include <stdlib.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <string.h> 
#include <sys/stat.h> 

int main(void) 
{ 
    void *mem; 
    size_t s = 512*1024*1024 - 16*1024; 
    while(1) 
    { 
     s += 1024; 
     int f = open("test.txt", O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR); 
     mem = malloc(s); 
     size_t written = write(f, mem, s); 
     free(mem); 
     close(f); 
     printf("(%ld) %lu\n", sizeof(size_t), written); 
    } 
    return 0; 
} 
+0

* westchnienie * Naprawdę powinienem był to zrozumieć. Myślałem o tym, a następnie szybko zapomniałem pomyśleć przed kompilacją. Dziękuję Ci! – staticfloat

+0

@staticfloat Próbowałem sprawdzić, czy mogę * udowodnić *, że był to przepełnienie stosu przy użyciu 'strace' i' gdb', ale nie mogłem - być może ktoś mógłby zasugerować, jak przepełnienie stosu może być definitywnie określone jako przyczyna wina. – trojanfoe

+0

W przypadku, gdy się zastanawiasz, to faktycznie rozwiązało problem. :) – staticfloat