Problème : segmentation fault (core dumped) en c

Fermé
fisae - Modifié le 23 mars 2023 à 22:05
[Dal] Messages postés 6181 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 22 mai 2024 - 24 mars 2023 à 11:39

Bonjour,

J'ai un soucis avec mon code. Il y a quelques semaine je l'ai lancé tout fonctionnait. Il y a quelques jours je le relance et j'ai cette erreur qui apparaît:

segmentation fault (core dumped)

alors que je n'ai rien touché! J'ai essayé gdb et valgrind mais je ne trouve toujours pas l'erreur. Pouvez-vous m'aidez?

Après avoir compilé avec gcc je lance:

./programme fichier.txt EDF 10

fichier.txt contient:

2
2 5 5
3 10 10

Le code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// La première variable “parametres” va nous permettre de connaître
// la taille du tableau à 2 dimensions. 
int parametres = 4; 

// Cette variable contient le temps mis en entrée lors de
// l'exécution du programme.
int temps_de_travail;

typedef struct grille {
    int nb_tache;
    int** matrice;
} GRILLE;

GRILLE * init_grille(int nb_tache);
void affiche_grille(GRILLE * grille_1);
void EDF(GRILLE* grille_1);

int main (int argc, char **argv) {
	int nombre_tache = 0, temps_de_charge = 0, periode = 0, echeance = 0;
	char * nom = argv[1];
	GRILLE * grille_1;
	temps_de_travail = atoi(argv[3]);

	if (argc!=4) {
		printf("Exit");
	} else {
		FILE * fichier = NULL;
		char * nom = argv[1];
		fichier = fopen(nom, "r");

		if (fichier != NULL) {
		    fscanf(fichier, "%d", &nombre_tache);
		    grille_1 = init_grille(nombre_tache);
		    int k = 0;
		    int p = 0;
		    while (!feof(fichier)) {
		        fscanf(
                    fichier, "%d %d %d",
                    &temps_de_charge, &periode, &echeance
                );
		        grille_1->matrice[k][p]=temps_de_charge;
		        p += 1 ;
		        grille_1->matrice[k][p]=periode;
		        p += 1 ;
		        grille_1->matrice[k][p]=echeance;
		        k += 1;
		        p = 0;
		    }
		    fclose(fichier);
		} else {
		    // On affiche un message d'erreur si le fichier ne s ouvre pas
		    printf("Impossible d'ouvrir le fichier");
		    free(grille_1);
		}

        affiche_grille(grille_1);

        if(strcmp(argv[2],"EDF") == 0) {
            printf("Algo EDF: \n");
            EDF(grille_1);
        } else if(strcmp(argv[2],"FP") == 0) {
            printf("Algo FP: \n");
            //FP(grille_1);
        } else {
            printf("Veuillez taper EDF ou FP\n");
        }
	}
	free(grille_1);
	return 0;
}

GRILLE * init_grille(int nb_tache) {
    GRILLE * grille_1 = (GRILLE*) malloc (sizeof(GRILLE));
    if (grille_1 == NULL) {
        printf("Erreur");
        exit(1);
    }
    grille_1->matrice  = calloc(nb_tache, sizeof(int *));
    if (grille_1->matrice == NULL) {
        printf("Erreur");
        free(grille_1);
        exit(1);
    }

    for (int i = 0; i < nb_tache ; i++) {
        grille_1->matrice[i] = calloc (parametres, sizeof(int));
        if (grille_1->matrice[i]==NULL) {
            for (int j = 0; j < i ; j++)
                free(grille_1->matrice[j]);
            free(grille_1->matrice);
            free(grille_1);
            printf("Erreur");
            exit(1);
        }
    }

    // Attribution de la valeur dans la structure
    grille_1->nb_tache = nb_tache; 

    // Initialisation de la matrice a 0
    for(int i = 0 ; i < grille_1->nb_tache ; i++) {
        for( int j = 0; j < parametres; j++)
            grille_1->matrice[i][j] = 0;
    }
    return grille_1;
}

void affiche_grille(GRILLE * grille_1) {
    for(int i = 0; i < grille_1->nb_tache ; i++) {
        for (int j = 0; j < parametres ; j++)
            printf("%d ", grille_1->matrice[i][j]);
        printf("\n");
    }
}

void EDF(GRILLE* grille_1) {
    int qui_ecrit = 100;
    int value = 0;
    int tableau[grille_1->nb_tache];
    for(int temps=0 ; temps<temps_de_travail ; temps++) {
        for (int k = 0; k < grille_1->nb_tache; k++) {
            if(temps%grille_1->matrice[k][2] == 0) {
                tableau[k]=grille_1->matrice[k][0];
                grille_1->matrice[k][3]= temps;
            }
        }

        for (int j = 0; j < grille_1->nb_tache; j++) {
            if (tableau[j] != 0) {
                if (qui_ecrit > grille_1->matrice[j][1] + grille_1->matrice[j][3]) {
                    qui_ecrit = grille_1->matrice[j][1] + grille_1->matrice[j][3];
                    value = j;
                }
            }
        }

        printf("%d ",value+1);
        tableau[value] -= 1;
        qui_ecrit = 100;
    }
}

5 réponses

PierrotLeFou
23 mars 2023 à 18:02

Que se passe-t-il si argc = 1 sur la ligne suivante?
    temps_de_travail = atoi(argv[3]);

    if (argc!=4)
Je n'ai pas tout vérifié, mais c'est un mauvais départ ...

0
[Dal] Messages postés 6181 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 22 mai 2024 1 084
Modifié le 23 mars 2023 à 19:23

Salut fisae,

Lorsque tu postes du code sur le forum CCM, fais le au moyen du bouton code comme tu l'as fait, mais en veillant à sélectionner dans la boite de dialogue le langage correspondant à ton code. Cela permet de poster ton code avec coloration syntaxique et numérotation des lignes, ce qui est plus pratique sur le forum pour se référer à une ligne en particulier.

Maintenant, sur ton problème.

Tu dis avoir utilisé valgrind et gdb sans succès...

Compiles-tu bien ton programme avec l'option -g qui permet d'insérer les symboles de débogage dans l'exécutable ?

$ gcc -g -Wall -Wextra main.c 
main.c: In function ‘main’:
main.c:24:8: warning: unused variable ‘nom’ [-Wunused-variable]
  char* nom = argv[1];
        ^~~
main.c:68:7: warning: ‘grille_1’ may be used uninitialized in this function [-Wmaybe-uninitialized]
       free(grille_1);
       ^~~~~~~~~~~~~~

Au passage, cela serait bien que ton programme compile proprement. Là ce n'est pas le cas.

valgrind et gdb sont d'accords sur le fait que le programme plante sur la ligne 53 en tentant d'accéder à une zone mémoire non allouée..., donc voilà ce que disent valgrind et gdb :

$ valgrind ./a.out fichier.txt EDF 10
==7993== Memcheck, a memory error detector
==7993== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7993== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==7993== Command: ./a.out fichier.txt EDF 10
==7993== 
==7993== Invalid read of size 8
==7993==    at 0x109310: main (main.c:53)
==7993==  Address 0x4a40350 is 0 bytes after a block of size 16 alloc'd
==7993==    at 0x4837B65: calloc (vg_replace_malloc.c:752)
==7993==    by 0x1094A7: init_grille (main.c:104)
==7993==    by 0x1092BC: main (main.c:45)
==7993== 
==7993== Invalid write of size 4
==7993==    at 0x109323: main (main.c:53)
==7993==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==7993== 
==7993== 
==7993== Process terminating with default action of signal 11 (SIGSEGV)
==7993==  Access not within mapped region at address 0x0
==7993==    at 0x109323: main (main.c:53)
==7993==  If you believe this happened as a result of a stack
==7993==  overflow in your program's main thread (unlikely but
==7993==  possible), you can try to increase the size of the
==7993==  main thread stack using the --main-stacksize= flag.
==7993==  The main thread stack size used in this run was 8388608.
==7993== 
==7993== HEAP SUMMARY:
==7993==     in use at exit: 616 bytes in 5 blocks
==7993==   total heap usage: 6 allocs, 1 frees, 4,712 bytes allocated
==7993== 
==7993== LEAK SUMMARY:
==7993==    definitely lost: 0 bytes in 0 blocks
==7993==    indirectly lost: 0 bytes in 0 blocks
==7993==      possibly lost: 0 bytes in 0 blocks
==7993==    still reachable: 616 bytes in 5 blocks
==7993==         suppressed: 0 bytes in 0 blocks
==7993== Rerun with --leak-check=full to see details of leaked memory
==7993== 
==7993== For counts of detected and suppressed errors, rerun with: -v
==7993== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Erreur de segmentation

(pour valgrind)

$ gdb -ex=r --args ./a.out fichier.txt EDF 10
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
Starting program: /home/raoul/z_perso/ccm/c/37816743/a.out fichier.txt EDF 10

Program received signal SIGSEGV, Segmentation fault.
0x0000555555555323 in main (argc=4, argv=0x7fffffffe128) at main.c:53
53			        grille_1->matrice[k][p]=temps_de_charge;
(gdb) 

(pour gdb)

La ligne 53 concernée est :

                        grille_1->matrice[k][p]=temps_de_charge;

Il est probable que tes indices que tu incrémentes dans ta boucle aillent au delà de la capacité de stockage prévue (ou que tu n'aies pas alloué suffisamment d'espace avec ton appel à calloc() en ligne 104 dont valgrind te précise la ligne aussi).

Autre remarque, sans avoir analysé ton code plus que cela : cette ligne est dans ta boucle de lecture avec de fscanf()  que tu mets dans un while comme ceci :

while (!feof(fichier))

Ce n'est pas comme cela que l'on lit le contenu d'un fichier au moyen d'une boucle.

Tester feof() n'a de sens qu'après avoir tenté une lecture.

Pour savoir si ta lecture a réussi, tu dois commencer par vérifier le retour de fscanf() auquel tu demandes de lire 3 entiers, et s'il ne lit pas 3 entiers, déterminer ensuite pourquoi (lecture d'un seul élément par exemple parce que l'élément suivant n'est pas un entier, ou parce qu'il n'y a plus rien à lire et que la fin du fichier est arrivée, ou une autre erreur de lecture).

0
PierrotLeFou
24 mars 2023 à 03:56

J'ai testé le code en mettant en commentaire les deux warning.
Ça plante si le programme lit une ligne de trop, mais ça semble marcher autrement.
(ma dernière ligne est vide)
La remarque de [Dal] est justement tout à fait pertinente.

0
[Dal] Messages postés 6181 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 22 mai 2024 1 084
24 mars 2023 à 11:05

Salut à tous et merci à mamiemando d'avoir modifié le code posté pour inclure la coloration syntaxique et numérotation des lignes.

Je pense que mamiemando a aussi un peu reformaté le code pour qu'il s'affiche mieux sur le forum (commentaires top longs, lignes de code trop longues, suppression des sauts de lignes vides multiples, etc.).

Du coup, la ligne 53 signalée par valgrind et gdb dans le code originel se trouve maintenant en ligne 45 du code posté sur le forum après reformatage.

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
[Dal] Messages postés 6181 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 22 mai 2024 1 084
Modifié le 24 mars 2023 à 11:47

Une façon simple de corriger le problème est de se servir de l'information prise en premier dans le fichier qui est censée indiquer le nombre de "nombre de tâches" contenues dans le fichier selon ma compréhension.

Chaque "tâche" nécessitant de lire 3 entiers.

Le code de cette partie du programme pourrait dès lors être :

                        if (fscanf(fichier, "%d", &nombre_tache) != 1) {
                                printf("Erreur de format: le fichier doit commencer "
                                                "par un entier représentant le nombre "
                                                "de tâches à lire (groupes de 3 "
                                                "entiers à lire)\n");
                                fclose(fichier);
                                return EXIT_FAILURE;
                        }

                        grille_1 = init_grille(nombre_tache);

                        int k = 0;
                        int p = 0;
                        int nombre_tache_lues = 0;

                        do {
                                if (fscanf(fichier, "%d %d %d",
                                        &temps_de_charge, &periode, &echeance) == 3) {
                                        grille_1->matrice[k][p]=temps_de_charge;
                                        p += 1 ;
                                        grille_1->matrice[k][p]=periode;
                                        p += 1 ;
                                        grille_1->matrice[k][p]=echeance;
                                        k += 1;
                                        p = 0;
                                        nombre_tache_lues++;
                                } else {
                                        printf("Erreur de lecture du fichier\n");
                                        fclose(fichier);
                                        return EXIT_FAILURE;
                                }
                        } while (nombre_tache_lues != nombre_tache);
                        fclose(fichier);

Pour un code plus propre, ci-dessus avant la ligne 30 "return EXIT_FAILURE;" on peut aussi libérer la mémoire allouée par l'appel à init_grille() avant de terminer le programme (bien que, de toutes façons, cela sera fait lorsque le programme se termine en redonnant la main au système d'exploitation), cependant, je n'ai pas regardé en détails comment la mémoire est allouée et comment elle est censée être libérée, et je laisse cela à fisae.


0