2012-04-20 12 views
5

Ero curioso di sapere che tipo di buffer size write() e read() potevano gestire su Linux/OSX/FreeBSD, quindi ho iniziato a giocare con programmi stupidi come il seguente:segfault su write() con buffer ~ 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; 
} 

Questo mi ha permesso di verificare come vicino ad una "barriera 8MB" apparente ho potuto ottenere prima di andare in segfault. Da qualche parte intorno al marchio di 8 MB, il mio programma muore, ecco un esempio di output:

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

Questo è lo stesso su OSX e Linux, tuttavia il mio VM di FreeBSD non è solo molto più veloce in esecuzione di questo test, può anche andare avanti per un bel po '! Ho testato con successo fino a 511 MB, che è solo una quantità ridicola di dati da scrivere in una sola chiamata.

Che cos'è che rende segreta la chiamata write() e come posso calcolare l'importo massimo che posso scrivere() in una singola chiamata, senza fare qualcosa di ridicolo come sto facendo adesso?

(Nota, tutti e tre i sistemi operativi sono 64 bit, OSX 10.7.3, Ubuntu 11.10, FreeBSD 9.0)

risposta

5

Il guastonon rientra write(), è un overflow dello stack. Prova questo:

#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

* sigh * Dovrei davvero averlo capito. Ci ho pensato, e poi prontamente ho dimenticato di pensare prima di compilare. Grazie! – staticfloat

+0

@staticfloat Ho provato a vedere se potevo * dimostrare * che era uno stack overflow usando 'strace' e' gdb' ma non potevo - forse qualcuno potrebbe suggerire come un overflow dello stack possa essere determinato in modo definitivo come causa di un colpa. – trojanfoe

+0

Nel caso ve lo stiate chiedendo, questo ha effettivamente risolto il problema. :) – staticfloat