IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

fclose - segmentation fault


Sujet :

C

  1. #1
    Candidat au Club
    Femme Profil pro
    Consultant ERP
    Inscrit en
    Mai 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Mai 2016
    Messages : 4
    Points : 2
    Points
    2
    Par défaut fclose - segmentation fault
    Bonsoir,

    voilà quelques heure que j'écume les forums en quête d'une solution à mon problème, je ne trouve malheureusement pas la solution (soit cela ne correspond pas, soit je ne comprends pas tout.

    Alors voilà, sous dev C++ mon code fonctionne très bien, mais sous Ubuntu, j'ai l'erreur "segmentation fault" qui apparaît. J'ai essayé de débuger avec gdb, voici le résultat :
    "Starting program: /home/ubuntu/workspace/chargevols
    *** Error in `/home/ubuntu/workspace/chargevols': free(): invalid size: 0x000000000060b010 ***

    Program received signal SIGABRT, Aborted.
    0x00007ffff7a4bcc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. "

    Voici le module fautif :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    void chargementVols(){
    	FILE *fichier_vols = fopen("vols2.txt","r");
    	int i = 0, j =0, retour;
     
    	char nomVille[30];
    	struct vol vol;
     
    	// test ouverture fichier
    	if (fichier_vols == NULL) {		// si ouverture fichier ko 
     
    		printf("Erreur de chargement du fichier des vols.\n");
    	} 
    	else {		// si ouverture fichier ok 
    		while (!feof(fichier_vols)){ // possibilite de faire un tableau dynamique avec un malloc et de supprimer #DEFINE NB_JONCTIONS ?
     
    			retour = fscanf(fichier_vols,"%d %s %s %s %s %s %d %s %s %f ", &vol.jour, vol.date, vol.num_vol, vol.villeDepart, vol.villeArrivee, vol.heure_depart, &vol.duree, vol.heure_arrivee, vol.nom_appareil, &vol.prix);
     
    			if (retour != EOF){
    				tabVol[i] = vol; // insertion de la ligne du fichier dans le nom de chaque structure jonction
    				i++;
    			}
    		}
     
    	}
     
    	fclose(fichier_vols), fichier_vols = NULL;
    }
    Merci pour votre aide !

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Bonjour et bienvenue,

    À première vue, en vrac :

    • feof() ne fait pas ce que tu crois. Et cela peut conduire ton programme à s'arrêter un cran trop loin, ce qui provoquerait un dépassement de tableau, qui à son tour provoquerait l'écrasement des variables locales déclarées à côté ;
    • Ce n'est pas une bonne idée, en C, de mélanger code et déclaration de variables même si le C99 le permet quand même ;
    • Les paramètres de ton fscanf() ont l'air correctement écrits, mais il faudra quand même veiller à ce qu'il n'y ait pas de dépassement de tampon. Il faudrait également que l'on voie comment ta structure « vol » est déclarée ;
    • Enfin et surtout : fclose() n'est pas capable de prendre en charge un pointeur NULL. La norme ne spécifie rien à ce sujet contrairement à free() ou realloc(). Si ton pointeur est NULL parce que fopen() a échoué, fclose() sera quand même appelée et risque de planter. Le programme ci-dessous déclenche une segfault sur Fedora :


    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
     
    int main (void)
    {
        fclose (NULL);
     
        return 0;
    }

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ ./programme
    Erreur de segmentation (core dumped)

    Bon courage.

  3. #3
    Candidat au Club
    Femme Profil pro
    Consultant ERP
    Inscrit en
    Mai 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Mai 2016
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdbool.h>
     
    	#define T_MAX_DEST		9	// Taille du tableau de destinations -> 10 destinations, mais tableau commence a 0
    	#define T_MAX_VILLE		30	// Nombre de carctere maximum dans les noms de villes
    	#define T_MAX_APPAREIL	13	// Nombre de carctere maximum dans les noms d'avions
    	#define NB_VOLS_INITIAL	224	// Nombre de vols disponibles au lancement de l'application (chargement du fichier vols.txt)
    	#define T_MAX_NOMFICHIER 30
     
    void chargementVols();
    struct vol
    {
    	int		jour;
    	char	date[11];
    	char	num_vol[7];
    	char	villeDepart[T_MAX_VILLE];
    	char	villeArrivee[T_MAX_VILLE];
    	int		duree;
    	char	heure_depart[6];
    	char	heure_arrivee[6];
    	char	nom_appareil[T_MAX_APPAREIL];
    	int		siegeRestant;
    	float	prix;
    };
     
    	Vol			tabVol[300];
     
    void main(){
    	chargementVols();
    }
     
    void chargementVols(){
    	FILE *fichier_vols = fopen("vols2.txt","r");
    	int i = 0, j =0, retour;
     
    	char nomVille[30],
    			ch,
    			junk[100];
    	struct vol vol;
     
    	// test ouverture fichier
    	if (fichier_vols == NULL) {		// si ouverture fichier ko 
     
    		printf("Erreur de chargement du fichier des vols.\n");
    	} 
    	else {		// si ouverture fichier ok 
    		while (ch = fgetc (fichier_vols) != EOF){ // possibilite de faire un tableau dynamique avec un malloc et de supprimer #DEFINE NB_JONCTIONS ?
     
    			retour = fscanf(fichier_vols,"%d %s %s %s %s %s %d %s %s %f ", &vol.jour, vol.date, vol.num_vol, vol.villeDepart, vol.villeArrivee, vol.heure_depart, &vol.duree, vol.heure_arrivee, vol.nom_appareil, &vol.prix);
    printf("while\n");
    			if (retour != EOF){
    				tabVol[i] = vol; // insertion de la ligne du fichier dans le nom de chaque structure jonction
    				i++;
    			}
     
    		}
     
    	}
    		fclose(fichier_vols);
    }
    Voilà le code complet de ce module.

    J'ai enlevé le pointeur null, je l'avais ajouté en désespoir de cause. Je cherche depuis tellement longtemps à comprendre ce qui fait l'erreur que je tente un peu tout au hasard.
    Je suis perdue au niveau de eof et feof...

    Merci pour ton aide

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Re-bonsoir,

    Ne te décourage pas : ton programme est tout-à-fait honorable pour quelqu'un qui débute et c'est bien parce qu'il est pratiquement valide en l'état qu'on l'examine avec la tout la rigueur qu'on porterait à un code professionnel.

    Pour feof(), cette fonction permet de vérifier l'état du bit de fin de lecture qui, lui, n'est en fait levé que par une autre fonction de la même famille lorsqu'il rencontre effectivement une fin de fichier ou une erreur de lecture. C'est donc la valeur de cette fonction qu'il faut vérifier MAIS je m'aperçois qu'en fait, tu le fais déjà. Ton feof() était donc justifié à sa place.

    Ta dernière ligne était également tout-à-fait correcte en elle-même. C'était une bonne idée d'avoir ramené ton pointeur à NULL après avoir refermé ton fichier. Ce qu'il ne faut pas faire, en revanche, c'est passer un pointeur déjà NULL à fclose() (à cause de l'échec de l'ouverture plus haut) car la norme ne prévoit pas que cette fonction soit capable de le reconnaître.

    La solution consiste en fait à reprendre tel quel le programme de ton premier commentaire et à déplacer la ligne concernée, de la ligne 26 à la ligne 23, c'est-à-dire juste avant l'accolade fermante de ton bloc « else » (et donc l'y placer à l'intérieur).

    Ainsi, si le pointeur de ton fichier est NULL pour quelque raison que ce soit, cette ligne ne sera jamais atteinte. Ce ne sera que si ton pointeur est bien testé « != NULL » (à partir de la ligne 13) et que ton fichier est officiellement considéré comme ouvert que cette ligne sera exécutée, en fin de traitement.

  5. #5
    Candidat au Club
    Femme Profil pro
    Consultant ERP
    Inscrit en
    Mai 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Mai 2016
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Merci beaucoup pour tes explications !

    C'est vraiment bête comme erreur, j'aurai dû la voir.
    Malheureusement, je viens d'essayer la solution que tu me propose et cela ne fonctionne toujours pas.

    Je remets le code modifié des fois que je n'ai pas compris...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    void chargementVols(){
    		FILE *fichier_vols = fopen("vols2.txt","r");
    	int i = 0, j =0, retour;
     
    	char nomVille[30];
    	struct vol vol;
     
    	// test ouverture fichier
    	if (fichier_vols == NULL) {		// si ouverture fichier ko 
     
    		printf("Erreur de chargement du fichier des vols.\n");
    	} 
    	else {		// si ouverture fichier ok 
    		while (!feof(fichier_vols)){ // possibilite de faire un tableau dynamique avec un malloc et de supprimer #DEFINE NB_JONCTIONS ?
     
    			retour = fscanf(fichier_vols,"%d %s %s %s %s %s %d %s %s %f ", &vol.jour, vol.date, vol.num_vol, vol.villeDepart, vol.villeArrivee, vol.heure_depart, &vol.duree, vol.heure_arrivee, vol.nom_appareil, &vol.prix);
     
    			if (retour != EOF){
    				tabVol[i] = vol; // insertion de la ligne du fichier dans le nom de chaque structure jonction
    				i++;
    			}
    		}
     		fclose(fichier_vols), fichier_vols = NULL;
    	}
     }

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Si ça ne marche toujours pas, c'est que cela plante ailleurs. Il va falloir trouver où.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    J'ai essayé de débuger avec gdb, voici le résultat :
    "Starting program: /home/ubuntu/workspace/chargevols
    *** Error in `/home/ubuntu/workspace/chargevols': free(): invalid size: 0x000000000060b010 ***
    
    Program received signal SIGABRT, Aborted.
    0x00007ffff7a4bcc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. "
    Plutôt qu'une segfault, c'est surtout un SIGABRT que l'on voit ici, déclenché par free(). La glibc est effectivement faite pour déclencher ce genre d'erreur en cas de corruption mémoire, ou lorsque l'on passe un pointeur invalide à free() en particulier.

    Relance ton programme sous gdb de la même façon puis, lorsque tu obtiens la même erreur, tape la commande « bt » (backtrace) pour obtenir la pile des appels de fonction et voir, au final, à quel endroit dans ton programme l'erreur se produit.

    N'oublie pas non plus de compiler ton programme avec l'option « -g » si tu utilises gcc, pour intégrer les informations de déboguage.

  7. #7
    Candidat au Club
    Femme Profil pro
    Consultant ERP
    Inscrit en
    Mai 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Mai 2016
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    J'ai fait la modification que tu m'as conseillé et vérifié les variables dans le code global et ça fonctionne !
    Merci beaucoup pour ton aide !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. fclose et segmentation fault
    Par thbkrshw dans le forum C
    Réponses: 9
    Dernier message: 18/11/2008, 12h38
  2. Segmentation Fault sur un fclose
    Par Beush dans le forum C
    Réponses: 9
    Dernier message: 30/11/2005, 19h30
  3. [REDHAT] Segmentation fault systematique
    Par mela dans le forum RedHat / CentOS / Fedora
    Réponses: 2
    Dernier message: 21/09/2004, 06h05
  4. Réponses: 13
    Dernier message: 13/07/2004, 15h41
  5. Comment contrer la "segmentation fault" ?
    Par guillaume_pfr dans le forum C
    Réponses: 15
    Dernier message: 08/08/2003, 13h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo