302 votes

Pourquoi la fonction gets est-elle si dangereuse qu'elle ne doit pas être utilisée ?

Lorsque j'essaie de compiler un code C qui utilise la fonction gets() avec GCC, j'obtiens cet avertissement :

(.text+0x34) : avertissement : la fonction `gets' est dangereuse et ne doit pas être utilisée.

Je me souviens que cela a quelque chose à voir avec la protection et la sécurité des piles, mais je ne sais pas exactement pourquoi.

Comment puis-je supprimer cet avertissement et pourquoi existe-t-il un tel avertissement concernant l'utilisation de l'outil de gestion de l'eau ? gets() ?

Si gets() est si dangereux, alors pourquoi ne pouvons-nous pas le supprimer ?

221voto

Thomas Owens Points 45042

Afin d'utiliser gets En toute sécurité, vous devez savoir exactement combien de caractères vous allez lire, afin que votre tampon soit suffisamment grand. Vous ne le saurez que si vous connaissez exactement les données que vous allez lire.

Au lieu d'utiliser gets vous voulez utiliser fgets qui a la signature

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

( fgets s'il lit une ligne entière, il laissera l'option '\n' dans la chaîne de caractères ; vous devrez faire avec).

gets est resté une partie officielle du langage jusqu'à la norme ISO C de 1999, mais il a été officiellement déprécié par la norme de 2011 et supprimé dans la norme de 2014. La plupart des implémentations C le supportent encore, mais au moins gcc émet un avertissement pour tout code qui l'utilise.

97 votes

En fait, ce n'est pas gcc qui avertit, c'est la glibc qui contient un pragme ou un attribut sur gets() qui fait que le compilateur émet un avertissement lorsqu'il est utilisé.

7 votes

@fuz en fait, ce n'est même pas seulement le compilateur qui avertit : l'avertissement cité dans l'OP a été imprimé par le linker !

26voto

Jack Points 61503

Parce que gets ne fait aucune vérification lors de la réception d'octets provenant de stdin et les mettre quelque part. Un exemple simple :

char array1[] = "12345";
char array2[] = "67890";

gets(array1);

Tout d'abord, vous êtes autorisé à saisir le nombre de caractères que vous souhaitez, gets ne s'en souciera pas. Ensuite, les octets dépassent la taille du tableau dans lequel vous les avez placés (dans ce cas-ci array1 ) écraseront tout ce qu'ils trouvent en mémoire car gets les écrira. Dans l'exemple précédent, cela signifie que si vous saisissez "abcdefghijklmnopqrts" peut-être, de façon imprévisible, il écrasera aussi array2 ou autre.

La fonction n'est pas sûre car elle suppose une entrée cohérente. NE L'UTILISEZ JAMAIS !

4 votes

Ce qui fait gets Le fait qu'elle n'ait pas de paramètre de longueur/comptage de tableau à prendre est carrément inutilisable ; s'il avait été là, ce serait juste une autre fonction standard C ordinaire.

1 votes

@legends2k : Je suis curieux de savoir quel est l'usage prévu pour gets et pourquoi aucune variante standard de fgets n'a été créée pour répondre aux cas d'utilisation où la nouvelle ligne ne doit pas faire partie de l'entrée ?

3 votes

@supercat gets était, comme son nom l'indique, conçu pour obtenir une chaîne de caractères à partir de stdin Cependant, la raison pour laquelle il n'y a pas de taille Le paramètre peut provenir de l'esprit de C : Faites confiance au programmeur. Cette fonction a été supprimée dans C11 et le remplacement donné gets_s prend la taille du tampon d'entrée. Je n'ai aucune idée de la fgets Mais il y a une partie qui ne l'est pas.

12voto

Gerd Klima Points 903

Vous ne pouvez pas supprimer les fonctions de l'API sans casser l'API. Si vous le faisiez, de nombreuses applications ne seraient plus compilées ou ne fonctionneraient plus du tout.

C'est la raison pour laquelle une référence donne :

La lecture d'une ligne qui déborde le tableau tableau pointé par s entraîne un comportement non défini. L'utilisation de fgets() est recommandée.

6voto

pmg Points 52636

J'ai lu récemment, dans un Message USENET à comp.lang.c que gets() est supprimé de la norme. WOOHOO

Vous serez heureux d'apprendre que le comité vient de voter (à l'unanimité, comme il s'avère) pour supprimer gets() de la liste des l'ébauche également.

3 votes

Il est excellent qu'elle soit supprimée de la norme. Toutefois, la plupart des implémentations la fourniront en tant qu'"extension non standard" pendant au moins les 20 prochaines années, en raison de la compatibilité ascendante.

1 votes

Oui, c'est vrai, mais quand vous compilez avec gcc -std=c2012 -pedantic ... gets() ne passera pas. (Je viens d'inventer le -std paramètre)

4voto

Yu Hao Points 40603

Dans C11(ISO/IEC 9899:201x), gets() a été supprimé. (Il est déprécié dans la norme ISO/IEC 9899:1999/Cor.3:2007(E)).

En plus de fgets() Le C11 présente une nouvelle alternative sûre gets_s() :

C11 K.3.5.4.1 Le gets_s fonction

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

Cependant, dans le Pratique recommandée section, fgets() est toujours préférable.

Le site fgets permet à des programmes correctement écrits de traiter en toute sécurité des lignes d'entrée trop longues pour être stockées dans le tableau de résultats. trop longues pour être stockées dans le tableau de résultats. En général, cela nécessite que les appelants de fgets payer attention à la présence ou à l'absence d'un caractère de nouvelle ligne dans le tableau de résultats. Pensez à d'utiliser fgets (ainsi que tout traitement nécessaire basé sur les caractères de nouvelle ligne) au lieu de gets_s .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X