11
votes

Pourquoi obtient () ne fonctionne pas?

Je suis programmée en C à UNIX, et j'utilise obtient code> pour lire les entrées du clavier. Je reçois toujours cet avertissement et le programme Arrêtez d'exécuter:

warning: this program uses gets(), which is unsafe.

c

4 commentaires

C'est une fonction dangereuse; Des attaques de dépassement de tampon peuvent être émises si des programmes utilisent de telles fonctions qui n'offrent pas la possibilité de vérifier la taille de la mémoire tampon.


Si j'utilise scanf () au lieu d'obtenir (), cela fonctionne, mais je dois lire 2 entrées du clavier et le programme s'arrête après avoir lu le premier. Pourquoi? Ceci est le code: Char utilisateur; TRAN PASS; printf ("ID IDER"); scanf ("% s", utilisateur); printf ("code PIN:"); scanf ("% s", passe);


@PEISKA: Le programme s'arrête après le premier parce qu'il vous attend d'entrer dans la seconde. Vous-même mettez vous-même cette seconde scanf là-bas. Pourquoi cela vous surprends-t-il que le programme "s'arrête" alors?


UTILISATEUR ET PASS doit être déclaré comme Tableaux de char, pas de caractères simples. Le spécificateur de conversion "% s" s'attend à ce que l'argument correspondant ait le type char * et que l'argument doit indiquer un tampon suffisamment long pour contenir la chaîne d'entrée et le terminateur 0 (le% non décoré " s "Specificateur de conversion expose la même faille de sécurité que obtient () à cet égard, mais il n'y a pas assez de place ici pour entrer dans cela en détail). Modifiez les déclarations de utilisateur et pass à chargeur [n]; Char Pass [m] où n et m sont les tailles dont vous avez besoin pour les deux tableaux.


4 Réponses :


16
votes

obtient code> est dangereux parce que vous lui donnez un tampon, mais vous ne le dites pas à quel point le tampon est grand. L'entrée peut écrire au-delà de la fin du tampon, explosant votre programme assez spectaculairement. Utilisation de fgets code> est plutôt un peu meilleur parce que vous le dites à quel point le tampon est grand, comme celui-ci: xxx pré>

... Donc, vous avez donc fourni les informations correctes, Ça n'écris pas devant la fin du tampon et souffle les choses. p>

légèrement OT, mais: p>

Vous n'êtes pas obligé d'utiliser un const int Code> Pour la taille de la mémoire tampon, mais je le ferais em> Je vous recommande de ne pas mettre un numéro littéral dans les deux endroits, car inévitablement, vous en allez en changer un mais pas l'autre plus tard. Le compilateur peut aider: P>

#define ARRAYCOUNT(a) (sizeof a / sizeof a[0])


6 commentaires

Si vous traitez avec un tableau de Char , il n'est pas nécessaire de diviser par tampon de tampon [0] comme Tailleof (char) == 1 Par définition, c'est-à-dire que l'appel de la fonction peut être simplifié à Fgets (tampon, tampon de taille de taille, stdin)


@Christoph: êtes-vous certain que Char sera un octet sur toutes les plates-formes et / ou que si elle est (dis) deux octets, que l'argument de taille BUF sur Les fgets seront appliqués comme caractères plutôt que octets ? La plupart des documents que j'ai vus ont dit des octets. Je suis sorti le jeu C un moment et je sais que ce genre de choses se sont plus compliquées, alors j'étais un peu défensive dans le code. Mais oui, @OP, si ces hypothèses sont sûrs, vous pouvez laisser le calcul avec un tableau char (mais pas des applications similaires de cet idiome avec int , long , etc.).


@ T.J. Crowder: la standard C défini char 1 octet.


@ T.J. Crowder: voir C99 Section 3.7.1 Qui indique que les caractères C sont un octet mono-octet et 6.5.3.4 §3, qui mentionne explicitement que tailleof (char) est toujours 1


C'est C. pas C ++ alors utilisez #define ou Enum.


@jamesdlin & @chrisotph: excellent, bon. (Comme je l'ai dit, je suis sorti du jeu C pendant un moment et je ne voulais pas induire en erreur en supposant que cela n'avait pas changé.)



5
votes

homme obtient dit:

Ne jamais utiliser obtient (). Parce que c'est impossible à dire sans savoir le données à l'avance combien de caractères obtient () va lire, et parce que obtient () continuera de stocker caractères au-delà de la fin du tampon, Il est extrêmement dangereux d'utiliser. Ce a été utilisé pour briser l'ordinateur Sécurité. Utiliser des fgets () à la place.


0 commentaires

2
votes

obtient () est dangereux. Il faut un paramètre, un pointeur sur un tampon de charme. Demandez-vous à quel point vous devez faire votre tampon et combien de temps un utilisateur peut taper l'entrée sans frapper la touche de retour.

Fondamentalement, il n'ya aucun moyen d'empêcher un débordement de tampon avec Obtient () - Utilisez des fgets ().


0 commentaires

8
votes

Comme mentionné dans les réponses précédentes, utilisez fgets code> au lieu de obtient code>.

mais ce n'est pas comme code> ne fonctionne pas à Tout, c'est juste très très dangereux. Je suppose que vous avez un bogue dans votre code qui apparaîtrait avec fgets code> aussi s'il vous plaît poster votre source. P>

edit strong> Basé sur les informations actualisées que vous avez données dans votre commentaire, j'ai quelques suggestions. P>

  • Je recommande de rechercher un bon tutoriel dans votre langue maternelle, Google est votre ami ici. En tant que livre, je recommanderais Le langage de programmation C P> li >

  • Si vous avez de nouvelles informations, il est judicieux de les modifier dans votre poste d'origine, surtout s'il s'agit d'un code, il sera plus facile pour les gens de comprendre ce que vous voulez dire. p> li>

  • Vous essayez de lire une chaîne, essentiellement d'un tableau de caractères, en un seul caractère, qui échouera bien sûr. Ce que vous voulez faire est de quelque chose comme ce qui suit. P>

    char username[256];
    char password[256];
    scanf("%s%s", username, password);
    


2 commentaires

Votre utilisation scanf est tout aussi mauvaise que obtient . (Évitez d'utiliser scanf aussi: c-faq.com/stdio/scanfprobs .html )


@jamesdlin Merci pour la tête, je ne connaissais pas le problème du débordement de la mémoire tampon, même si j'ai eu d'autres problèmes avec Scanf avant.