2010-03-25 18 views
5

Escribo un daemon de alta carga que debe ejecutarse en FreeBSD 8.0 y en Linux también. El objetivo principal de daemon es pasar archivos solicitados por su identificador. El identificador se convierte en el tamaño del archivo/nombre de archivo local mediante solicitud a db. Y luego uso las llamadas secuenciales mmap() para pasar bloques de archivos con send().compruebe si la dirección mmap'ed es correcta

Sin embargo, a veces hay una falta de coincidencia de tamaño de archivo en db y tamaño de archivo en el sistema de archivos (tamaño real < en db). En esta situación, he enviado todos los bloques de datos reales y cuando se mapea el siguiente bloque de datos, mmap no devuelve ningún error, solo la dirección habitual (también he comprobado la variable errno, es igual a cero después de mmap). Y cuando daemon intenta enviar este bloque, obtiene falla de segmentación. (Este comportamiento está emitido de forma garantizada en FreeBSD 8.0 amd64)

Estaba usando la verificación segura antes de abrir para asegurar el tamaño con la llamada stat(). Sin embargo, la vida real me muestra que segfault todavía se puede plantear en situtaions raras.

Entonces, mi pregunta es ¿hay alguna manera de verificar si el puntero es accesible antes de quitarle la referencia? Cuando abrí core en gdb, gdb dice que la dirección dada está fuera de límite. Probablemente haya otra solución que alguien pueda proponer.

#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; 
} 

Respuesta

2

Por supuesto que no puedo demostrar de aquí, pero tengo la fuerte sospecha de que sólo hay un error libro de mantenimiento en el código. Si llamas a mmap y pasas un tamaño, y tiene éxito, no deberías obtener SIGSEGV.

Le recomiendo que aplique valgrind a su investigación.

En muchos sistemas Linux/proc/PID/maps le mostrará qué regiones se asignan con qué permisos de acceso.

+0

He puesto un ejemplo de código que ilustra el problema en el mensaje principal. Este código emula la creación del archivo y luego lo cambia de tamaño mientras ha sido procesado con mmap. En el sistema Linux tengo error de bus en el tercer paso, en FreeBSD hay SegFault. – reddot