Comment lire (en toute sécurité) l’entrée de l’utilisateur avec la fonction getline


  • FrançaisFrançais


  • Lire des chaînes en C était autrefois une chose très dangereuse à faire. Lors de la lecture des entrées de l’utilisateur, les programmeurs peuvent être tentés d’utiliser le gets fonction de la bibliothèque standard C. L’utilisation pour gets est assez simple :

    char *gets(char *string);

    C’est, gets lit les données de l’entrée standard et stocke le résultat dans une variable de chaîne. En utilisant gets renvoie un pointeur sur la chaîne, ou la valeur NULL si rien n’a été lu.

    Comme exemple simple, nous pourrions poser une question à l’utilisateur et lire le résultat dans une chaîne :

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

    int
    main()
    {
      char city[10];                       // Such as "Chicago"

      // this is bad .. please don't use gets

      puts("Where do you live?");
      gets(city);

      printf("<%s> is length %ld\n", city, strlen(city));

      return 0;
    }

    Entrer une valeur relativement courte avec le programme ci-dessus fonctionne assez bien :

    Where do you live?
    Chicago
    <Chicago> is length 7

    Programmation et développement

    Cependant, le gets La fonction est très simple et lira naïvement les données jusqu’à ce qu’elle pense que l’utilisateur a terminé. Mais gets ne vérifie pas que la chaîne est suffisamment longue pour contenir l’entrée de l’utilisateur. La saisie d’une valeur très longue entraînera gets pour stocker plus de données que la variable de chaîne ne peut en contenir, ce qui entraîne l’écrasement d’autres parties de la mémoire.

    Where do you live?
    Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch
    <Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch> is length 58
    Segmentation fault (core dumped)

    Au mieux, écraser des parties de la mémoire casse simplement le programme. Au pire, cela introduit un bogue de sécurité critique où un mauvais utilisateur peut insérer des données arbitraires dans la mémoire de l’ordinateur via votre programme.

    C’est pourquoi le gets La fonction est dangereuse à utiliser dans un programme. En utilisant gets, vous n’avez aucun contrôle sur la quantité de données que votre programme tente de lire de l’utilisateur. Cela conduit souvent à un débordement de tampon.

    Le fgets La fonction a toujours été la méthode recommandée pour lire les chaînes en toute sécurité. Cette version de gets fournit un contrôle de sécurité en ne lisant qu’un certain nombre de caractères, passés en argument de la fonction :

    char *fgets(char *string, int size, FILE *stream);

    Le fgets la fonction lit à partir du pointeur de fichier et stocke les données dans une variable de chaîne, mais uniquement jusqu’à la longueur indiquée par size. Nous pouvons tester cela en mettant à jour notre exemple de programme pour utiliser fgets à la place de gets:

    #include <stdio.h>

    #include <string.h>

    int

    main()

    {

    char city[10]; // Such as “Chicago”

    // fgets is better but not perfect

    puts(“Where do you live?”);

    fgets(city, 10, stdin);

    printf("<%s> is length %ld\n", city, strlen(city));

    return 0;

    }

    Si vous compilez et exécutez ce programme, vous pouvez entrer un nom de ville arbitrairement long à l’invite. Cependant, le programme ne lira que suffisamment de données pour tenir dans une variable de chaîne de size=10. Et parce que C ajoute un caractère nul (‘\0’) à la fin des chaînes, cela signifiefgets ne lira que 9 caractères dans la chaîne :

    Where do you live?
    Minneapolis
    <Minneapol> is length 9

    Bien que cela soit certainement plus sûr que d’utiliser fgets pour lire l’entrée de l’utilisateur, il le fait au prix de “couper” l’entrée de votre utilisateur si elle est trop longue.

    Une solution plus flexible pour lire des données longues consiste à permettre à la fonction de lecture de chaîne d’allouer plus de mémoire à la chaîne, si l’utilisateur a entré plus de données que la variable ne peut en contenir. En redimensionnant la variable de chaîne selon les besoins, le programme dispose toujours de suffisamment d’espace pour stocker l’entrée de l’utilisateur.

    Le getline fonction fait exactement cela. Cette fonction lit l’entrée d’un flux d’entrée, tel que le clavier ou un fichier, et stocke les données dans une variable de chaîne. Mais contrairement à fgets et gets, getline redimensionne la chaîne avec realloc pour s’assurer qu’il y a suffisamment de mémoire pour stocker l’entrée complète.

    ssize_t getline(char **pstring, size_t *size, FILE *stream);

    Le getline est en fait un wrapper à une fonction similaire appelée getdelim qui lit les données jusqu’à un caractère délimiteur spécial. Dans ce cas, getline utilise une nouvelle ligne (‘\n’) comme délimiteur, car lors de la lecture d’une entrée utilisateur à partir du clavier ou d’un fichier, les lignes de données sont séparées par un caractère de nouvelle ligne.

    Le résultat est une méthode beaucoup plus sûre pour lire des données arbitraires, une ligne à la fois. Utiliser getline, définissez un pointeur de chaîne et définissez-le sur NULL pour indiquer qu’aucune mémoire n’a encore été réservée. Définissez également une variable “taille de chaîne” de type size_t et lui donner une valeur nulle. Quand vous appelez getline, vous utiliserez des pointeurs vers les variables de chaîne et de taille de chaîne et indiquerez où lire les données. Pour un exemple de programme, nous pouvons lire sur l’entrée standard :

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

    int
    main()
    {
      char *string = NULL;
      size_t size = 0;
      ssize_t chars_read;

      // read a long string with getline

      puts("Enter a really long string:");

      chars_read = getline(&string, &size, stdin);
      printf("getline returned %ld\n", chars_read);

      // check for errors

      if (chars_read < 0) {
        puts("couldn't read the input");
        free(string);
        return 1;
      }

      // print the string

      printf("<%s> is length %ld\n", string, strlen(string));

      // free the memory used by string

      free(string);

      return 0;
    }

    Comme le getline lit les données, il réallouera automatiquement plus de mémoire pour la variable de chaîne selon les besoins. Lorsque la fonction a lu toutes les données d’une ligne, elle met à jour la taille de la chaîne via le pointeur et renvoie le nombre de caractères lus, y compris le délimiteur.


    Enter a really long string:
    Supercalifragilisticexpialidocious
    getline returned 35
    <Supercalifragilisticexpialidocious
    > is length 35

    Notez que la chaîne inclut le caractère délimiteur. Pour getline, le délimiteur est le retour à la ligne, c’est pourquoi la sortie comporte un saut de ligne. Si vous ne voulez pas de délimiteur dans votre valeur de chaîne, vous pouvez utiliser une autre fonction pour remplacer le délimiteur par un caractère nul dans la chaîne.

    Avec getline, les programmeurs peuvent éviter en toute sécurité l’un des pièges courants de la programmation en C. Vous ne pouvez jamais savoir quelles données votre utilisateur pourrait essayer d’entrer, c’est pourquoi l’utilisation de gets est dangereux, et fgets est gênant. Plutôt, getline offre un moyen plus flexible de lire les données utilisateur dans votre programme sans casser le système.

    Source

    La Rédaction

    L'équipe rédactionnnelle du site

    Pour contacter personnellement le taulier :

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Copy code