2010-03-25 7 views
5

Ich schreibe einen High-Loaded-Daemon, der auf FreeBSD 8.0 und unter Linux laufen sollte. Der Hauptzweck von Daemon besteht darin, Dateien zu übergeben, die von ihrem Bezeichner angefordert werden. Der Bezeichner wird über die Anfrage in db in den lokalen Dateinamen/Dateigröße konvertiert. Und dann benutze ich sequentielle mmap() Aufrufe, um Dateiblöcke mit send() zu übergeben.überprüfe, ob die mmap-Adresse korrekt ist

Es gibt jedoch manchmal nicht übereinstimmende Dateigröße in db und Dateigröße auf Dateisystem (realsize < Größe in db). In dieser Situation habe ich alle realen Datenblöcke gesendet und wenn der nächste Datenblock gemappt wird - mmap gibt keine Fehler zurück, nur die übliche Adresse (ich habe auch die Fehlernummer überprüft, sie ist gleich Null nach mmap). Und wenn der Daemon versucht, diesen Block zu senden, erhält er Segmentierungsfehler. (Dieses Verhalten wird garantiert auf FreeBSD 8.0 amd64 ausgegeben)

Ich benutzte Safe-Check vor dem Öffnen, um die Größe mit Anruf sicherzustellen. Das wirkliche Leben zeigt mir jedoch, dass in seltenen Situationen immer noch segfault auftreten kann.

Also meine Frage gibt es eine Möglichkeit zu überprüfen, ob der Zeiger zugänglich ist, bevor es Dereferenzierung? Wenn ich Core in Gdb geöffnet habe, sagt Gdb, dass die angegebene Adresse außerhalb des Bereichs liegt. Wahrscheinlich gibt es eine andere Lösung, die jemand vorschlagen kann.

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

Antwort

2

Natürlich kann ich es von hier aus nicht beweisen, aber ich vermute stark, dass Sie nur einen Buchhaltungs Fehler in Ihrem Code. Wenn Sie mmap aufrufen und eine Größe übergeben, und es erfolgreich ist, sollten Sie SIGSEGV nicht erhalten.

Ich empfehle, dass Sie Valgrind auf Ihre Untersuchung anwenden.

Auf vielen Linux-Systemen/proc/PID/maps zeigt Ihnen, welche Regionen mit welchen Zugriffsberechtigungen zugeordnet sind.

+0

Ich habe Code-Beispiel, das das Problem in Head Post veranschaulicht. Dieser Code emuliert die Erstellung einer Datei und ändert dann die Größe, während sie mit mmap fortgefahren wurde. Auf Linux-System habe ich Bus-Fehler im dritten Schritt, auf FreeBSD gibt es SegFault. – reddot