Léa-Linux & amis :   LinuxFR   GCU-Squad   GNU
Erreur lors du mappage d'un fichier en mémoire
Envoyé par: jacques35

Bonsoir ;

Désirant mapper un fichier en mémoire, j'ai trouvé le programme suivant.
Le problème c'est que lorsque vient le moment d'afficher le contenu du fichier, un message d'erreur (Segmentation fault) est généré.

L'autre problème est qu'au momment de libérer la mémoire, nouveau message d'erreur (erreur sur munmap).

Help please.

#include <sys/mman.h>
#include <sys/stat.h> /* pour la fonction stat */
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {
int i, Desc, Taille;
char *AdrMem;
struct stat StructFichier;

if (argc !=2) {
fprintf(stderr, ">>> Syntaxe : %s fichier \n", argv[0]);
exit(1);
}

Desc = open(argv[1],O_RDONLY);

if(Desc== -1) {
perror("erreur sur open");
exit(1);
}

if (stat(argv[1], &StructFichier) == -1) {
perror("erreur sur stat");
close (Desc);
exit(1);
}
Taille = StructFichier.st_size;
printf("%d est la taille du fichier %s \n" ,Taille , argv[1]);

AdrMem = (char *)mmap(NULL, StructFichier.st_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, Desc, 0);

if(AdrMem == NULL) {
perror ("erreur sur mmap");
close (Desc);
exit(1);
}
close(Desc);

printf("Voici le contenu du fichier projete:\n");
for (i=0; i< Taille; i++)
putchar(AdrMem);

if ( munmap(AdrMem, Taille)== -1) {
perror("erreur sur munmap");
exit(1);
}
}

Poste le Thursday 14 April 2005 20:29:53
Répondre     Citer    
Re: Erreur lors du mappage d'un fichier en mémoire
Envoyé par: Raph__

Salut,
Je suis encore débutant, donc je ne peux pas faire une analyse complète de ce code. Mais ca ne m'empeche pas de trouver où ca cloche smiling smiley

Citation

if(AdrMem == NULL) {
perror ("erreur sur mmap");
close (Desc);
exit(1);
}

Déjà ici c'est pas bon.

man mmap :
Citation

VALEUR RENVOYÉE
mmap renvoie un pointeur sur la zone de mémoire, s'il réussit. En cas
d'échec il retourne MAP_FAILED (-1) et errno contient le code
d'erreur.

munmap renvoie 0 s'il réussit. En cas d'échec -1 est renvoyé et errno
contient le code d'erreur (probablement EINVAL).
La condition if (AdrMem == NULL) est donc foireuse : if (AdrMem == MAP_FAILED)
Le man nous dit
Citation

errno contient le code d'erreur.
Le code d'erreur devrait donc nous aider...
Citation

fprintf (stderr, "Error mmap : %s\n", strerror (errno));

On compile, on execute :
Citation

Error mmap : Permission denied

On y voit déjà un peu plus clair.


Quand j'aurai compris comment fonctione mmap je te ferai signe. smiling smiley

[mauvaise langue]
Ton code tu ne l'aurais pas pris ici :[cedric.cnam.fr] par hasard ? (de toutes facons, celui qui est proposé sur cette page est aussi foireux que celui que tu as proposé).
Quand on voit le cv de l'auteur, ca fait quand meme rigoler.
[/mauvaise langue]

A Ciao smiling smiley

Poste le Friday 15 April 2005 15:47:26
Répondre     Citer    
Re: Erreur lors du mappage d'un fichier en mémoire
Envoyé par: Raph__

re
Citation

printf ("%d %d %d %d\n", PROT_READ, PROT_WRITE, MAP_FILE, MAP_SHARED);

1 2 0 1

1 | 2 => 3 mmap connait cette valeur !?
0 | 1 => 1 completement inutile.

Je ne comprends pas le but de l'operation.
Essaye de modifier l'argument "prot" et le flag MAP, ca marche impec.
Je continu mes petites recherches, en attendant les conseils d'un expert seraient les bienvenues. smiling smiley

Voir /usr/include/asm/mman.h

A Ciao !

Poste le Friday 15 April 2005 16:25:36
Répondre     Citer    
Re: Erreur lors du mappage d'un fichier en mémoire
Envoyé par: Raph__

rere
Je m'excuse pour le multi postage, je m'y prends mal. smiling smiley

Citation
Raph__
1 | 2 => 3 mmap connait cette valeur !?

Je me reponds à moi même : oui cette écriture a un sens, elle permet de gérer les droits.

Citation

PROT_READ|PROT_EXECUTE donne r-x
PROT_READ|PROT_WRITE donne rw
PROT_READ|PROT_WRITE|PROT_EXECUTE donne rwx
(je ne l'avais pas vu sous cette angle)

Par contre je ne vois toujours pas l'interet du MAP_FILE | MAP_SHARED.

LE PROBLEME !
Vient du droit d'écriture, si l'on supprime ce droit, ca fonctionne. Meme en etant root ca ne marche pas. Donc... (lol)
Re man
Citation

L'argument prot indique la protection que l'on désire pour
cette zone de mémoire, ET NE DOIT PAS entrer en conflit avec le mode
d'ouverture du FICHIER.

Citation

Desc = open(argv[1], O_RDWR);
et non
Citation

Desc = open(argv[1],O_RDONLY);

Voila c'est finit, au revoiiiir. smiling smiley)

Poste le Friday 15 April 2005 17:11:15
Répondre     Citer    
Re: Erreur lors du mappage d'un fichier en mémoire
Envoyé par: jacques35

Bonjour ;

Grand merci pour les explications données. J'ai fait quelques corrections de façon très intuitives qui me donnent satisfaction. Ceci dit, je ne suis pas sûr de tout comprendre.

Voici le nouveau code qui fonctionne. Je l'espère orthodoxe ;-). Il me reste à comprendre bie à fond tout ça.

la ligne : printf ("%d %d\n", PROT_READ, MAP_SHARED);
genère 1 | 1.
Que dois je comprendre ?

#include <sys/mman.h>
#include <sys/stat.h> /* pour la fonction stat */
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char *argv[]) {
int i, Desc, Taille;
char *AdrMem;
struct stat StructFichier;

if (argc !=2) {
fprintf(stderr, ">>> Syntaxe : %s fichier \n", argv[0]);
exit(1);
}

// Ouverture du fichier en lecture seule
Desc = open(argv[1],O_RDONLY);

if(Desc== -1) {
perror("erreur sur open");
exit(1);
}

// Obtention de la taille du fichier a l'aide de la fonction stat
if (stat(argv[1], &StructFichier) == -1) {
perror("erreur sur stat");
close (Desc);
exit(1);
}
Taille = StructFichier.st_size;
printf("%d est la taille du fichier %s \n" ,Taille , argv[1]);

AdrMem = (char *)mmap(NULL, StructFichier.st_size, PROT_READ, MAP_SHARED, Desc, 0);

if(AdrMem == MAP_FAILED) {
fprintf (stderr, "Error mmap : %s\n", strerror (errno));
close (Desc);
exit(1);
}
printf ("%d %d\n", PROT_READ, MAP_SHARED);
// On peut fermer le fichier
close(Desc);

printf("Voici le contenu du fichier projete:\n");
for (i=0; i< Taille; i++)
putchar(AdrMem);

// Liberation de l'espace memoire
if ( munmap(AdrMem, Taille)== -1) {
perror("erreur sur munmap");
exit(1);
}
}

Poste le Saturday 16 April 2005 13:18:32
Répondre     Citer    
Re: Erreur lors du mappage d'un fichier en mémoire
Envoyé par: Raph__

Salut,

Citation

AdrMem = (char *)mmap(NULL, StructFichier.st_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, Desc, 0);

Je ne comprennais pas l'écriture PROT_READ | PROT_WRITE et MAP_FILE | MAP_SHARED.
Ne connaissant pas les valeurs de ces constantes, j'ai utilisé printf pour les connaitres. ( elles sont définies dans /usr/include/asm/mman.h, comme je l'ai dit plus haut).
Pour moi il était évident que si l'on donnait le parametre PROT_WRITE, on avait forcement le droit de lecture. Donc pour moi PROT_READ | PROT_WRITE était une erreur.
Mais le fichier mman.h m'a permis de comprendre, que l'on peut combiner les differentes valeurs de PROT, pour donner les droits que l'on souhaite à la zone mémoire allouée par mmap. Donc utilisation du | (OU inclusif).
mmap "regarde" les bits qui sont à un pour le parametre PROT.
Citation

PROT_READ mmap recoit 001 r-- (binaire)
PROT_WRITE mmap recoit 010 -w-
PROT_EXEC mmap recoit 100 --x
PROT_READ | PROT_WRITE mmap recoit 011 rw-
PROT_READ | PROT_WRITE | PROT_EXEC mmap recoit 111 rwx

Si on avait eu un PROT_WRITE | PROT_EXEC je ne me serais pas posé cette question.

Puis le MAP_FILE | MAP_SHARED à finit de m'enfoncer. smiling smiley
MAP_FILE vaut 0 ! Pourquoi faire une operation dessus ?
Alors là c'est pas trés clair, j'ai fait quelques recherches et il semblerait que MAP_FILE soit conservée pour des raisons de compatibilités avec d'anciennes applications, mais l'écriture MAP_FILE | MAP_* semble obsolete.
A confirmer tout de meme.

Citation
jacques35
la ligne : printf ("%d %d\n", PROT_READ, MAP_SHARED);
genère 1 | 1.
Que dois je comprendre ?
Cette ligne provoque l'affichage : 1 1
Et permet juste de connaitre les valeurs de ces deux constantes.

Remarque : Dans ton dernier code, on a juste un acces en lecture dans la zone mémoire.
Je connais pas tes besoins, mais la correction du premier code que tu as donné serait :
Citation

Desc = open(argv[1], O_RDWR);

mmap (NULL, Taille, PROT_READ | PROT_WRITE, MAP_SHARED, Desc, 0);

A Ciao smiling smiley

Poste le Saturday 16 April 2005 14:48:50
Répondre     Citer    
Re: Erreur lors du mappage d'un fichier en mémoire
Envoyé par: jacques35

Merci pour ces précisions.

En effet j'ai modifié le code pour limiter l'accès en lecture. En fait il s'agit de projeter un fichier .wav en mémoire pour pouvoir l'écrire par la suite sur /dev/dsp.

Poste le Tuesday 19 April 2005 20:52:53
Répondre     Citer    

Veuillez vous authentifier auparavant pour commenter.

 

Ce forum !
Erreur lors du mappage d'un fichier en mémoire
Pour poser vos questions sur les scripts shell, le Perl, le C, etc... Attention : nous ne sommes pas des spécialistes du dev, ce forum est juste pour de petites aides ponctuelles concernant le développement et les outils de développement.

Sauf mention contraire, les documentations publiées sont sous licence Creative-Commons