• [^] # Re: Buffer overflow power

    Posté par . En réponse au message les sémaphores nommés. Évalué à 4.

    char n[20], p[20];

    printf("Nom:"); fgets(n, sizeof(n) * sizeof(char), stdin);
    printf("Prenom:"); fgets(p, sizeof(p) * sizeof(char), stdin);

    c'est plus secure quand même.

    Presque.

    Comme n est du type char[20], on a: sizeof(n) == 20 * sizeof (char). Donc ta formule est incorrecte. Note qu'elle renvoie le bon résultat numérique, mais seulement par coïncidence: la façon dont elle est exprimée laisse croire que, pour un tableau, sizeof tab renvoie le nombre d'éléments, alors qu'elle renvoie le nombre d'éléments fois la taille de l'élément (le nombre d'éléments est obtenu par sizeof array / sizeof array[0]).
    Tu obtiens le bon résultat dans ton cas, seulement parce que sizeof (char) == sizeof (unsigned char) == sizeof (signed char) == 1. C'est garanti par la norme C (6.5.3.4p1 du n1224).
    Dans tout autre cas, sizeof MonType >= 1. Pour fgets(), ça n'a aucun impact, vu qu'il attend des char mais, pour toute autre fonction, ta formule indiquerait à la fonction que le tableau fourni en paramètre a une taille plus grande qu'en réalité, d'où des risques de buffer overflow, ou de perte mémoire (je pense aussi à malloc(), si tu demandes plus de mémoire que ce dont tu as besoin, ce sont des pertes sèches...).

    Pour en revenir à ce bout de code précis, si on suppose que tu as mis simplement sizeof n, alors ton programe est plus sûr... jusqu'à ce que l'utilisateur rentre un nom de (au moins) 19 caractères... Dans ce cas, le premier fgets() mange les 19 premiers caractères, y ajoute un '0円', et rend la main en laissant le '\n' dans stdin. Le deuxième fgets() mangera tout de suite le '\n', et retournera après y avoir ajouté le '0円'.
    Tu obtiendras donc un nom de 19 caractères, et un prénom qui vaut '\n'. Idem pour le prénom, sachant que les caractères en trop dans stdin seront lus plus tard dans le code, et pas forcément là où on s'y attendrait...

    Avec fgets(), il faut tester la présence de '\n' dans le buffer, et lire la suite s'il n'y est pas (sauf si on a rencontré la fin du flux, évidemment). La bonne réponse est donc fgets(n, sizeof n, stdin); suivi d'une boucle de vérification de la présence de '\n' (avec strchr()) ou de fin du flux, et d'une relecture si nécessaire; le tout encapsulé dans une fonction générique, pour que tu n'aies pas à la recoder 20 fois (note aussi que ça se trouve sur le vaste internet, cd. http://cbfalconer.home.att.net/download/ggets.zip par exemple, faite par un connaisseur du C et "régulier" sur comp.lang.c).

    P.S.: fflush(stdin) a un comportement indéfini, ça n'est autorisé que sur stdout.

    Pas seulement. 7.19.5.2p2:
    If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
    Donc stderr ou tout autre flux sortant est valide pour fflush().