View Full Version : Errore apertura file creato
Algeroth
05-12-2005, 15:13
//Apertura del file sala.txt
file_sala = open("sala.txt",O_RDWR|O_CREAT,0660);
if (file_sala == -1) {
printf("Errore nell'apertura del File\n");
exit(-1);
}
//Mapping del file sala.txt nello spazio di indirizzamento del processo server
int filelen = lseek(file_sala, 0, SEEK_END);
txt = (Posto*)mmap(0, filelen, PROT_READ|PROT_WRITE, MAP_SHARED, file_sala, 0);
if(txt == NULL){
printf("Mapping del file sala.txt fallito, si prega di verificare il problema\n");
exit(-1);
}
Perchè mi da errore? :muro:
ilsensine
05-12-2005, 15:18
Perché non descrivi l'errore che ti da e il tipo di test che stai facendo?
nb(1) ovviamente il check su mmap è sbagliato. NULL è un valore legittimo. Se la mmap fallisce, ritorna MAP_FAILED (ovverio ~0)
nb(2) In caso di errore, usa perror. Ad es:
file_sala = open("sala.txt",O_RDWR|O_CREAT,0660);
if (file_sala == -1) {
perror("open");
exit(-1);
}
Algeroth
05-12-2005, 15:26
l' errore che mi da è quello sul file mapping.
Ossia se mi apro il file in quella modalità mi da errore il file mapping("Mapping del file sala.txt fallito").
Se il file lo creo manualmente non mi da questo tipo di errore e tutto funziona; con quali modalità devo aprire il file o con quali devo fare il file mapping?
Ciao e grazie
:mc:
Algeroth
05-12-2005, 15:58
Problema risolto
Sono un imbecille
Grazie comunque a tutti :D :D :D :D :D
ilsensine
05-12-2005, 15:58
Ti ho già detto che il confronto
if(txt == NULL)
è sbagliato; devi confrontare con MAP_FAILED. Mi sembra impossibile che, nel tuo caso, la mmap ritorna NULL comunque.
Quindi riscrivi il codice così e controlla quello che dice:
if(txt == MAP_FAILED){
perror("mmap");
exit(-1);
}
l' errore che mi da è quello sul file mapping.
Ossia se mi apro il file in quella modalità mi da errore il file mapping("Mapping del file sala.txt fallito").
Se il file lo creo manualmente non mi da questo tipo di errore e tutto funziona; con quali modalità devo aprire il file o con quali devo fare il file mapping?
Confermo che se si crea (anche a mano) il file con qualcosa dentro, il codice funziona. Se invece il file lo fai creare alla open, il file avrà lunghezza 0 e per questo motivo la mmap ti restituisce NULL. Quindi si dovrebbe testare se il puntatore restituito è diverso da MAP_FAILED e da NULL.
ilsensine
06-12-2005, 08:30
Non sapevo che mmap ritornasse NULL se la regione da mappare ha dimensione 0. Molto astuto, così becchi subito accessi erronei da parte del codice.
Quindi si dovrebbe testare se il puntatore restituito è diverso da MAP_FAILED e da NULL.
Non sono c'accordo, basta testare MAP_FAILED. Il codice deve essere fatto per accedere al massimo alla dimensione della mappatura; quindi una regione di grandezza 0 non dovrebbe essere mai acceduta. Se provi a farlo è un bug, e ti becchi un meritato segmentation fault.
Non sono c'accordo, basta testare MAP_FAILED. Il codice deve essere fatto per accedere al massimo alla dimensione della mappatura; quindi una regione di grandezza 0 non dovrebbe essere mai acceduta. Se provi a farlo è un bug, e ti becchi un meritato segmentation fault.
Allora... MAP_FAILED, da quanto ho potuto vedere, è definito come ((void*) -1). Quindi, tradotto come un indirizzo, sarebbe 0xFFFFFFFF. È chiaro che né NULL (0x0), né MAP_FAILED sono indirizzi validi e tantomeno accessibili.
Sul fatto, come dici tu, che una regione di grandezza 0 non dovrebbe essere acceduta, è vero ma dipende da cosa ci devi fare.
Supponiamo:
int filelen = lseek (...);
txt = (Posto*)mmap (...);
if (txt != MAP_FAILED)
{
for (i=0; i<filelen; i++)
{
...utilizzo di txt...
}
}
In questo caso se filelen è 0, txt non verrà mai usato, quindi non ci sono problemi. Ma supponi che invece del ciclo for, devi usare txt in una memcpy. Otterresti un bel segmentation fault!
Quindi o ti fai un exception handling (non so come ma in qualche modo), oppure testi se txt è NULL, oppure ancora, più a monte, testi se filelen è zero e a questo punto non fai neanche la mmap e fai altro.
Tra l'altro mi sembra stupido che la mmap possa restituire MAP_FAILED (-1). Tutte le principali funzioni (almeno che io conosco) che restituiscono un puntatore, ritornano un NULL in caso di errore (es. malloc, strchr, strstr, fgets, ecc...).
goku@big:/tmp$ cat mmap_test.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(void)
{
int filelen;
void *map;
int fd = open("sala.txt", O_RDWR | O_CREAT, 0660);
if (fd == -1) {
perror("open()");
exit(1);
}
filelen = lseek(fd, 0, SEEK_END);
map = mmap(0, filelen, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
if (map == MAP_FAILED) {
perror("mmap()");
close(fd);
exit(1);
}
puts("mapped file!");
close(fd);
munmap(map, filelen);
return 0;
}
goku@big:/tmp$ gcc mmap_test.c -o mmap_test -Wall
goku@big:/tmp$ ./mmap_test
mmap(): Invalid argument
goku@big:/tmp$ echo pinocchio ha fatto colazione >>sala.txt
goku@big:/tmp$ ./mmap_test
mapped file!
goku@big:/tmp$
Mi sembra vada tutto bene: uno degli argomenti (a occhio la lunghezza 0) non viene accettato.
Mi sembra vada tutto bene: uno degli argomenti (a occhio la lunghezza 0) non viene accettato.
mumble... su che distribuzione linux??? A me, se la lunghezza del file è zero, la mmap restituisce NULL e non MAP_FAILED (ho provato su una "vecchia" Caldera eDesktop 2.4 e su una Slackware 9.1).
mumble... su che distribuzione linux???
Slackware 10.2 (kernel 2.6.14.2).
Per curiosita' ho provato anche su una Gentoo aggiornata con lo stesso risultato postato sopra.
ilsensine
06-12-2005, 10:51
Allora... MAP_FAILED, da quanto ho potuto vedere, è definito come ((void*) -1). Quindi, tradotto come un indirizzo, sarebbe 0xFFFFFFFF. È chiaro che né NULL (0x0), né MAP_FAILED sono indirizzi validi e tantomeno accessibili.
NULL è un indirizzo valido. Conosco almeno un programma che ci mappa memoria.
Supponiamo:
int filelen = lseek (...);
txt = (Posto*)mmap (...);
if (txt != MAP_FAILED)
{
for (i=0; i<filelen; i++)
{
...utilizzo di txt...
}
}
In questo caso se filelen è 0, txt non verrà mai usato, quindi non ci sono problemi. Ma supponi che invece del ciclo for, devi usare txt in una memcpy. Otterresti un bel segmentation fault!
Una memcpy con numero di byte 0 non fa nulla, quindi non ottieni nessun segfault.
Tra l'altro mi sembra stupido che la mmap possa restituire MAP_FAILED (-1). Tutte le principali funzioni (almeno che io conosco) che restituiscono un puntatore, ritornano un NULL in caso di errore (es. malloc, strchr, strstr, fgets, ecc...).
Esegui questo programma e fammi sapere il tuo risultato:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
int main(int argc, char **argv) {
char *map = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
if(map==MAP_FAILED) {
perror("mmap");
exit(-1);
}
sprintf(map, "sto scrivendo all'indirizzo 0x%08lx!!\n", (unsigned long) map);
write(fileno(stderr), map, strlen(map));
return 0;
}
Una memcpy con numero di byte 0 non fa nulla, quindi non ottieni nessun segfault.
Sì, ovvio, se usi come lunghezza 0 nella memcpy. Io dicevo in generale, ho detto memcpy per fare un esempio ma se invece fai una strchr, siamo daccapo: segmentation fault.
Esegui questo programma e fammi sapere il tuo risultato:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
int main(int argc, char **argv) {
char *map = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
if(map==MAP_FAILED) {
perror("mmap");
exit(-1);
}
sprintf(map, "sto scrivendo all'indirizzo 0x%08lx!!\n", (unsigned long) map);
write(fileno(stderr), map, strlen(map));
return 0;
}
In effetti mi scrive "sto scrivendo all'indirizzo 0x00000000!!". :eek:
Desidero precisare che pur conoscendo di nome la funzione mmap(), non l'avevo mai usata (prima di fare le prove per questo thread). Quindi per evitare di "fare notte" vorrei precisare che:
1) Il puntatore NULL (0x0) è, per definizione, un puntatore non valido, usato oltretutto da una caterba di funzioni per segnalare un errore. L'accesso all'indirizzo 0x0 causa quindi, generalmente, un segmentation fault.
2) Che esista una funzione "particolare" come la mmap (che opera a livello di sistema sulla mappatura della memoria) solo sui sistemi Linux/Unix e che ti mappa un blocco di memoria all'indirizzo 0x0 ... beh, questa, come direbbe qualcuno ... è un'altra storia! Non lo sapevo :( ma posso capirlo e mi può stare bene. ;)
ilsensine
06-12-2005, 11:43
1) Il puntatore NULL (0x0) è, per definizione, un puntatore non valido, usato oltretutto da una caterba di funzioni per segnalare un errore. L'accesso all'indirizzo 0x0 causa quindi, generalmente, un segmentation fault.
Questo perché è una ovvia convenzione stabilire che un allocatore di memoria restituisca "0" in caso di errore. La mmap però non è un semplice allocatore di memoria; ti consente di fare quello che vuoi con i tuoi indirizzi _virtuali_ (0 incluso!)
Il fatto che all'indirizzo 0 ci puoi trovare "qualcosa di valido", non è una semplice alchimia del mio programmino. Gli x86 in modalità reale, se non ricordo male, hanno il vettore di interruzioni all'indirizzo 0 (verificabile tramite qualsiasi DOS); alcuni processori hanno memoria _fisica_ di un qualche tipo all'indirizzo 0 (ad es. lo StrongARM ha la flash), che coincide con la memoria vista dal programma se operi senza mmu. In queste situazioni, se scrivi su NULL non ottieni necessariamente un segfault (forse qualcosa di meno divertente :D)
Questo perché è una ovvia convenzione stabilire che un allocatore di memoria restituisca "0" in caso di errore. La mmap però non è un semplice allocatore di memoria; ti consente di fare quello che vuoi con i tuoi indirizzi _virtuali_ (0 incluso!)
Sono d'accordo con te.
Il fatto che all'indirizzo 0 ci puoi trovare "qualcosa di valido", non è una semplice alchimia del mio programmino. Gli x86 in modalità reale, se non ricordo male, hanno il vettore di interruzioni all'indirizzo 0 (verificabile tramite qualsiasi DOS); alcuni processori hanno memoria _fisica_ di un qualche tipo all'indirizzo 0 (ad es. lo StrongARM ha la flash), che coincide con la memoria vista dal programma se operi senza mmu. In queste situazioni, se scrivi su NULL non ottieni necessariamente un segfault (forse qualcosa di meno divertente :D)
Anche questo è vero. Non conosco gli StrongARM ma mi ricordo benissimo (e quanto ci ho lavorato...) che nel MSDOS (modalità reale quindi), all'indirizzo 0 c'era la tabella degli interrupt. E andare a scriverci lì sopra per sbaglio era ... molto divertente! ;)
Quindi per riassumere. Il puntatore NULL per convenzione non è valido, ed è quindi buona norma testare puntatori, ecc... prima dell'utilizzo.
La mmap() e architetture hardware particolari sono da trattare a parte.
ilsensine
07-12-2005, 12:26
Sì, ovvio, se usi come lunghezza 0 nella memcpy. Io dicevo in generale, ho detto memcpy per fare un esempio ma se invece fai una strchr, siamo daccapo: segmentation fault.
mmm mi ero perso questo...
un strchr su una regione ottenuta con mmap è un bug, a meno che non hai verificato preventivamente (ad es. con strnlen) che la regione termina con '\0'. Puoi andare in segfault anche se il file non è vuoto; basta che sia allineato alla pagina, non contenga zeri, e non contenga il carattere che stai cercando con strchr.
Per queste applicazioni (ovvero con dati forniti "dall'esterno", ad es. letti da un file) meglio memchr.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.