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 :

Interférence scanf et fgets


Sujet :

C

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 5
    Par défaut Interférence scanf et fgets
    Bonjour,

    Je butte depuis hier soir sur un problème étrange d'erreur de segmentation. Je fais appel à un scanf, et le programme plante immédiatement après uniquement si un fgets est présent plus loin dans le code, dans un autre scope, avec des instructions les séparant.
    Voilà quelques snippets:

    main.c (cf l13 et l17)
    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
     
    #include "../misc.h"
    #include "../parse_maps.h"
    #include "../search.h"
     
    int main(int argc, char *argv[])
    {
        unsigned long remote_offset;
        pid_t remote_pid;
        map_line_t map_line;
        FILE* map_file = NULL;
     
        validate_start(argc, argv, &remote_pid); // Le scanf est dans le corps de cette fonction
     
        open_map_file(remote_pid, map_file);
     
        load_map_data_for_filename(map_file, &map_line, "[heap]"); // Le fgets est dans le corps de cette fonction
     
       //remote_offset = memory_offsets_where_string_equals(remote_pid, map_line, "heapvartwo");
        //printf("Offset is at %#lx\n", remote_offset);
        //fclose(map_file);
        return 0;
    }
    misc.c
    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
     
    #include "misc.h"
     
    #include <stdio.h>
    #include <stdlib.h> // atoi
     
    void validate_start(int argc, char* argv[], pid_t* pid)
    {
        char tmp[100];
     
        if (argc == 2) {
            sprintf(tmp, "%s", argv[1]);
            *pid = atoi(tmp);
        }
        else
        {
            puts("Enter the PID of target process: ");
            int lol;
            while(scanf("%d", &lol) == 0) // C'est un peu buggé, mais ça fait le taf. Le programme plante après que ce scanf réussisse, cf les commentaires plus bas
            {
                puts("Not a valid number, try again:");
                getchar();
            }
        }
     
        printf("yeye"); // Ceci ne s'affiche jamais, j'ai une erreur de segmentation avant sauf
        // quand je commente la ligne du fgets dans la fonction montrée plus bas
     
    }
    finalement, parse_maps.c
    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
     
    #include "parse_maps.h"
     
    #include <stdio.h>
    #include <fcntl.h>
    #include <string.h>
    #include "valuetypes.h"
     
    void open_map_file(pid_t pid, FILE* map_file)
    {
    //code
    }
     
    void read_map_line(char* line, map_line_t* map_line)
    {
    //code
    }
     
    void load_map_data_for_filename(FILE* map_file, map_line_t* map_line, char* filename)
    {
        char tmp[1000];
        map_line_t curr_map;
     
        while (fgets(tmp, 999, map_file) != NULL) // Le fgets de cette ligne fait planter le scanf de la première fonction
        {
            // read_map_line(tmp, &curr_map);
     
            // if(strcmp(curr_map.filename, filename) == 0)
            // {
            //     read_map_line(tmp, map_line);
            //     return;
            // }
        }
    }

    Je peine vraiment à comprendre mon erreur, je suis sûr que c'est quelque chose de stupide comme un pointeur mal utilisé, mais pour l'instant j'ai cherché sans résultat..

    Je compile avec GCC 8.2.1 ou tcc 0.9.27 avec le même résultat.

    Merci de votre aide!

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par yhu420 Voir le message
    Je peine vraiment à comprendre mon erreur, je suis sûr que c'est quelque chose de stupide comme un pointeur mal utilisé, mais pour l'instant j'ai cherché sans résultat..
    Et t'as pensé à mettre quelque chose dans "map_file" ??? Parce que la fonction open_map est vide et même si elle avait un code, ben comme le "map_file" qu'elle reçoit n'est qu'une copie du "map_file" de ton main, c'est comme si elle ne faisait rien du tout (toujours le même principe universel : si une fonction doit modifier une variable qu'elle reçoit, il faut alors lui passer l'adresse de cette variable).

    Sinon les détails non bloquants mais qui me gênent
    1. tu fais un scanf() pour saisir un nombre => il faut que tu supprimes le '\n' qui est resté dans stdin
    2. ta chaine est de 1000 mais tu fais un fgets() de 999. Tu perds un octet (fgets() garde toujours une place pour le '\0').
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 5
    Par défaut
    En ce qui concerne tes remarques, elles sont très pertinentes, je vais les corriger tout de suite.

    Sinon je comprends toujours pas.. Peu importe la valeur de map_file, ça ne devrait pas influencer le comportement de mon scanf qui n'a aucun lien avec lui. En effet le "yeye" de debug ne s'affiche pas avant même que map_file ne soit utilisé.

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 5
    Par défaut
    Je crois avoir fixé les erreurs, j'ai tout inclus dans un zip

    test2.zip

    EDIT: en revanche, le problème persiste!

    EDIT2: C'est bon j'ai trouvé, mais je n'ai toujours pas compris l'origine du problème.
    En fait c'est juste que le printf "yeye" ne marchait pas. Je l'ai remplacé par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        fflush(stdin); fflush(stdout);
        printf("yeye");
        printf("yoouuo");
    mais sans changement. L'erreur venait effectivement du map_file qui était mal chargé.

    Merci

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par yhu420 Voir le message
    Je crois avoir fixé les erreurs, j'ai tout inclus dans un zip
    Je viens de regarder. Et surtout la fonction "open_map()" que je reproduis ici
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void open_map_file(pid_t pid, FILE** map_file)
    {
        char tmp[100];
     
        sprintf(tmp, "/proc/%d/maps", pid);
     
        *map_file = fopen(tmp, "r");
        if (map_file == NULL)
        {
            printf("Error: cant open map file");
            exit(EXIT_FAILURE);
        }
    }
    Alors effectivement tu l'as bien corrigée. Mais il reste une question: pourquoi tu lui passes la variable à remplir ???
    Moi je l'aurais écrite plus simplement ainsi
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    FILE *open_map_file(pid_t pid)
    {
        char tmp[100];
     
        sprintf(tmp, "/proc/%d/maps", pid);
     
        return fopen(tmp, "r");
    }

    surtout que ça enlève aussi un autre problème de ton code: on ne quitte jamais un programme quand une fonction ne peut pas faire son travail. Si la fonction n'y arrive pas, alors on remonte le souci à l'appelant qui prendra une décision (dans le pire des cas il remontera le souci à son propre appelant et ainsi de suite jusqu'au main()).

    Citation Envoyé par yhu420 Voir le message
    En fait c'est juste que le printf "yeye" ne marchait pas. Je l'ai remplacé par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        fflush(stdin); fflush(stdout);
        printf("yeye");
        printf("yoouuo");
    On ne flushe pas stdin. Le but de cette fonction est de purger les écritures en attente. Or stdin est un buffer de lecture. Ce genre d'instruction n'est pas inclus dans la norme. Alors chez certains éditeurs de librairies elle est implémentée mais chez certains autres elle ne l'est pas. Bref pour résumer cela produit dans le pire des cas un comportement indéterminé.
    Et si cette purge n'est pas implémentée, c'est pour une raison toute simple: dans ton code, tu es sensé savoir maîtriser le contenu de stdin, c'est à dire que si tu en viens à le lire, tu dois savoir alors ce qu'il est sensé contenir à ce moment là pour le lire correctement sans y laisser de résidu.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 12/04/2018, 18h39
  2. fgets + scanf et gestion des espaces
    Par Yunchi dans le forum Débuter
    Réponses: 7
    Dernier message: 02/03/2009, 15h35
  3. Scanf, fgets et buffer.
    Par SAKDOSS dans le forum Bibliothèque standard
    Réponses: 6
    Dernier message: 15/01/2008, 08h58
  4. scanf vs fgets
    Par _SamSoft_ dans le forum C
    Réponses: 86
    Dernier message: 06/09/2007, 14h27
  5. Réponses: 6
    Dernier message: 10/09/2002, 03h35

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