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 :

vider une partie du buffer pour l'utilisation de fscanf (fscanf securisé)


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut vider une partie du buffer pour l'utilisation de fscanf (fscanf securisé)
    Bonjour à tous!
    Alors j'ai une petite question sur l'utilisation de fscanf (et globalement sur toute cette famille de fonction)

    Supposons que j'ai un fichier contenant un texte formaté comme suit:
    (string) (string) (int)
    bidul truc 20

    Je veux récupérer à l'aide de la fonction fscanf: bidul truc et 20.

    Mais supposons que la taille de mon tableau permettant de recevoir la première chaine de caractère soit de 3.
    Alors j'utilise bien sur "%2s",comme ça, je ne produirais pas d'overflow!
    Cependant, je veux que le deuxième tableau contienne truc. Or je m'aperçois qu'en faite il contient dultruc: le dul venant de la première chaine de caractère (car le buffer contient ces lettres!)

    J'aimerai savoir comment forcer fscanf à lire les 2 premières lettres de bidul, d'"oublier" les lettres dul (pour ne pas faire d'overflow), et de continuer son fonctionnement normal, c'est à dire de mettre la deuxième chaine de caractère "truc" dans la variable dédiée...

    Alors je pense qu'on va me conseiller d'utiliser un getchar()! Oui, mais je ne veux pas: j'aimerais faire ça uniquement avec fscanf: c'est juste dans le but d'apprendre!!!
    Je sais aussi que %* permet "d'oublier" les caractères: oui, mais moi je veux juste oublier dul, pas toute la chaine!!

    Pourrais-t-on m'expliquer comment faire?
    Par avance merci!!

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 502
    Par défaut
    Tu es sûr que ce n'est pas « scanf() » plutôt que « fprintf() », que tu utilises ?

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Oh ZUT: tellement l'habitude d'écrire ça!
    je vais corriger mon post! mais oui, c'est fscanf!!!

    Méga désole pour cette erreur stupide!

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 502
    Par défaut
    Tu peux faire suivre ton « %s » par un opérateur d'affectation-suppression « * », qui permet de lire normalement un élément puis de le faire passer à la trappe plutôt que de le stocker derrière le pointeur correspondant. Ainsi :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
        scanf ("%10s%*s %10s%*s",str1,str2);

    … lira une chaîne de dix octets maximum puis ignorera la suite jusqu'au blanc, avant de recommencer.

    L'inconvénient, c'est que si l'élément à lire est moins long que la taille passée, alors l'opérateur en question va faire disparaître la chaîne suivante. Ce n'est donc pas une solution parfaite.

  5. #5
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
       char tab1[8], tab2[8];
       int d;
       scanf("%7s%*[^ ]%7s%*[^ ]%d",tab1, tab2,&d);
    devrait traiter correctement chaque champ en les limitant à 7 caractères (+ le '\0' terminal) maximum.

    [EDIT] Cette solution est incorrecte

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Super merci!
    Dès que je pourrais, j'essaierai ce code!

    Est-ce qu'on peut considérer ce code comme sécurisé? Dans le sens ou par exemple, on ne peux pas faire d'overflow?

  7. #7
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Il faut quand même que le format entré soit
    blancs0n|chaine1n|espaceblancs1n|chaine1n|espaceblancs1n|entier|...
    où
      - blancs0n est une chaine vide ou ne contenant que des blancs (0 ou plusieurs)
        un blanc est un caractère pour lequel isspace() == VRAI :
        espace (' '), ('\f'), ('\n'),('\r'), ('\t'), ('\v')....
      - chaine1n est une chaine de caractères ne contenant pas de blancs et non vide  
      - espaceblancs1n est une  chaine ne contenant que des blancs (1 ou plusieurs) 
        et dont au moins un blanc est un espace (on s'est limité à l'exclusion 
        de ' ' dans %*[^ ])
      - entier est une chaine de caractères représentant un entier
    
    Il conviendrait de plus de vérifier que le retour du scanf() est bien 3

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Merci beaucoup diogene et Obsidian

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Bonjour, c'est re moi

    j'ai encore un petit probleme avec le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    scanf("%7s%*[^ ]%7s%*[^ ]%d",tab1, tab2,&d);
    En effet, tout marche comme il faut tant que la première chaîne de caractère est supérieure à 7. Mais, si je mets une chaâne de caractère inférieur à 7, alors ça ne fonctionne plus: les variables ne contiennent plus ce quelle devraient contenir.
    Je pense que lorsque ma chaîne de caractère inférieur à 7 alors le "%*^ ] supprime des choses alors qu'il ne devrait pas, et donc toute la lecture est décalée, et donc les variables ne contiennent pas ce qu'il faut.

    Pouvez-vous m'aider à gérer ce cas?

    Par avance merci!!!!!

  10. #10
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Peux-tu donner la chaine de caractères que tu utilises pour mettre en évidence ce problème et le contenu obtenu pour tab1, tab2 et d ?

    Ce test
    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
    #include <stdio.h>
    int main(void)
    {
         char tab1[256], tab2[256];
         int d;
         char buffer1[] = "123  abcdefghi 321";
         char buffer2[] = "123456789  abcdefghi 321";
         sscanf(buffer1,"%7s%*[^ ]%7s%*[^ ]%d",tab1, tab2,&d);
         printf("Buffer = <%s>\n",buffer1);
         printf("Tab1=<%s> Tab2=<%s> d=%d\n\n", tab1,tab2,d);
         sscanf(buffer2,"%7s%*[^ ]%7s%*[^ ]%d",tab1, tab2,&d);
         printf("Buffer = <%s>\n",buffer2);
         printf("Tab1=<%s> Tab2=<%s> d=%d\n\n", tab1,tab2,d);
        return 0;
    }
    donne bien :
    Buffer = <123  abcdefghi 321>
    Tab1=<123> Tab2=<abcdefg> d=321
    
    Buffer = <123456789  abcdefghi 321>
    Tab1=<1234567> Tab2=<abcdefg> d=321
    

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Bonjour et merci de ta réponse rapide

    Effectivement, toi ça marche bien. J'ai du faire une erreur, je vais comparer ton code et le mien!

    En attendant, voici ce que j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    scanf("%7s%*[^ ]%7s%*[^ ]%d",t1, t2,&a);
    printf("%s ",t1);
    printf("%s ", t2);
    printf("%d \n",&a)
    j'entre en console:
    aze rty 2
    et ça me renvoie:
    aze ttet 152381020
    Bizard nn?

  12. #12
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%d \n",a) // pas &a

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Regarde, j'ai exécute ton code test et mon résultat est différent:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Buffer = <123  abcdefghi 321>
    Tab1=<123> Tab2=<b��|2> d=50
     
    Buffer = <123456789  abcdefghi 321>
    Tab1=<1234567> Tab2=<abcdefg> d=321
    Le premier test se comporte comme mon code: il ne réagi pas comme prévue!

    C'est étrange nn?

  14. #14
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    J'avais testé ce code avec un compilateur ANSI sans problèmes.

    A la suite de ton message Je l'ai testé aussi sur un autre compilateur (gcc) et effectivement il y a ce problème.
    En fait le scanf renvoie alors 1, ce qui montre que le deuxième %s n'a pas été exécuté (et tab2 et d non chargés).
    La question était pourquoi.
    Ce fonctionnement défectueux se produit tant que la première chaine comporte moins de 8 caractères, autrement dit si après la lecture du premier champ, il n'y a que des blancs avant le second champ. On peut en déduire que dans ce cas, le %*[^ ] (lire tout jusqu'au premier blanc exclu) échoue si le premier caractère est un blanc.

    Consultation de la norme C99 où on trouve ceci : si la longueur de l'élément lu est 0 alors il y a échec dû à une mauvaise correspondance entre le format et la donnée entrée. Le comportement est donc dans ce cas bien défini par la norme : il n'y a pas de correspondance et la conversion doit s'arrêter. Et apparemment ceci s'applique aussi aux champs supprimés par %*...

    On comprend ce comportement pour les champs qui sont stockés, puisque dans ce cas la donnée ne peut être obtenue, mais pour les champs qui sont sautés (et qui ne sont même pas comptabilisés), c'est stupide.
    Enfin, c'est comme ça et j'ignorais ce "détail" .

    Je me demande aussi si c'est un comportement nouveau introduit par C99 ou si mon compilateur ANSI n'était lui pas conforme.

    De toute façon, la conclusion est le rejet de cette "solution".

  15. #15
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    On peut sur ce même thème envisager :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
         i = fscanf(f,"%7s%*[^ ]%7s%*[^ ]%d",tab1, tab2,&d);
         switch(i)
         {
             case 1 : i+= fscanf(f,"%7s%*[^ ]%d", tab2,&d);
                      if(i==3) break;
             case 2 : i+= fscanf(f,"%d",&d);
         }
         if (i !=3) printf("erreur fichier") ;
         else printf("Tab1=<%s> Tab2=<%s> d=%d\n\n", tab1,tab2,d);

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 59
    Par défaut
    Oh super! ca marche parfaitement!
    En plus, c'est très astucieux cette méthode avec le switch!!! Je ne connaissais pas!

    Merci beaucoup! J'ai appris plein de choses!

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 25/03/2014, 15h17
  2. mettre une partie de buffer à 0
    Par madmax51 dans le forum Débuter
    Réponses: 20
    Dernier message: 04/06/2010, 08h53
  3. Réponses: 6
    Dernier message: 26/11/2009, 15h19
  4. memcpy, memmove etc. d'une partie du buffer
    Par muquet dans le forum Débuter
    Réponses: 5
    Dernier message: 19/07/2007, 17h49

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