Ce qui rend une bibliothèque C standard fonction dangereux, et quelle est l'alternative?
Lors de l'apprentissage de C I viennent régulièrement dans toutes les ressources qui recommandent de certaines fonctions (par exemple,gets()
) ne doivent jamais être utilisés, car ils sont difficiles ou impossibles à utiliser en toute sécurité.
Si la bibliothèque C standard contient un certain nombre de ces de "ne jamais utiliser les fonctions d', il semble nécessaire d'apprendre une liste d'entre eux, ce qui les rend dangereux, et que faire à la place.
Jusqu'à présent, j'ai appris que les fonctions dont:
- Ne peut être empêché de l'écrasement de la mémoire
- Ne sont pas garantis à zéro à la fin d'une chaîne
- Maintenir interne de l'état entre les appels
sont communément considérés comme étant dangereux à utiliser. S'il existe une liste de fonctions qui présentent ces comportements? Il existe d'autres types de fonctions, qui sont impossibles à utiliser en toute sécurité?
- La liste complète de securecoding : securecoding.cert.org/confluence/display/seccode/...
- La Question est en cours de discussion sur meta et peut attirer l'attention inhabituelle meta.stackoverflow.com/questions/385216/...
- Il y a des énergumènes comme
setjmp()
etlongjmp()
qui n'ont pas été mentionnés; ils sont à la problématique en général, en particulier pour l'origine l'utilisation prévue de saut entre la procédure en cours et une autre procédure encore sur la pile d'appel au-dessus de la procédure en cours. Ils sont difficiles à utiliser, vraiment bien. Traitement du Signal peut également être problématique. Le standard C règles sont très restrictives; POSIX règles sont plus sensibles. - Cela dépend beaucoup du contexte. MISRA C des directives de codage (à l'origine pour les systèmes embarqués dans les voitures — MISRA est le Moteur de l'Industrie de la Fiabilité des Logiciels de l'Association) s'opposent à l'utilisation de
malloc()
et les amis, et les hors la loi de la variable de tableaux de longueur, et la flexibilité des membres du groupe. Il y a des raisons pour le faire dans le cadre de laquelle les lignes directrices ont été rédigées. Ces interdits ne sont pas nécessairement utiles ailleurs.
Vous devez vous connecter pour publier un commentaire.
Dans les vieux jours, la plupart des fonctions de chaîne n'avait pas de vérification des limites. Bien sûr ils ne pouvaient pas juste supprimer les anciennes fonctions, ou de modifier leurs signatures afin d'inclure une limite supérieure, qui permettrait de casser la compatibilité. Maintenant, pour la presque totalité de ces fonctions, il existe une autre version "n". Par exemple:
Et plus.
Voir aussi https://github.com/leafsr/gcc-poison qui est un projet de création d'un fichier d'en-tête qui provoque la gcc pour signaler une erreur si vous utilisez une mauvaise fonction.
char*
et la-dessus (et d'autres) les fonctions de manipulation destrcpy_s
/strncpy_s
). La honte ils ne sont pas plus largement utilisé, carstrncpy
est toujours ouverte pour du programmeur dérapages et n'est donc pas entièrement sûr de dépassements de la mémoire tampon.Oui,
fgets(..., ..., STDIN)
est une bonne alternative àgets()
, parce qu'il prend un paramètre de taille (gets()
a en effet été retiré de la norme C entièrement en C11). Notez quefgets()
n'est pas exactement une baisse-dans le remplacement pourgets()
, parce que les anciens comprendront la résiliation de\n
personnage si il y avait de la place dans la mémoire tampon pour une ligne complète à lire.scanf()
est considérée comme problématique dans certains cas, plutôt que de tout droit sortie de "mal", parce que si l'entrée n'est pas conforme au format attendu qu'il peut être impossible de récupérer judicieusement (il ne vous laisse pas rembobiner la saisie et essayez à nouveau). Si vous pouvez simplement abandonner sur une mauvaise mise en forme d'entrée, il est utilisable. Une "meilleure" alternative ici est d'utiliser une fonction d'entrée commefgets()
oufgetc()
pour lire des morceaux de l'entrée, puis l'analyser avecsscanf()
ou analyser avec la manipulation des chaînes de fonctions commestrchr()
etstrtol()
. Voir aussi ci-dessous pour un problème spécifique avec le"%s"
indicateur de conversion enscanf()
.Ce n'est pas une norme en fonction de C, mais la BSD et POSIX fonction
mktemp()
est généralement impossible à utiliser en toute sécurité, car il y a toujours un TOCTTOU condition de concurrence entre le test de l'existence du fichier et ensuite de le créer.mkstemp()
outmpfile()
sont de bons substituts.strncpy()
est un peu délicate fonction, car il n'a pas la valeur null à la fin de la destination, si il n'y avait pas de place pour elle. Malgré l'apparente nom générique, cette fonction a été conçue pour créer un style spécifique de la chaîne qui diffère de l'ordinaire C chaînes - chaînes stockées dans un champ de largeur fixe où le terminateur null n'est pas nécessaire si la chaîne remplit le champ exactement (UNIX d'origine des entrées de répertoire ont été de ce style). Si vous ne disposez pas d'une telle situation, vous devriez probablement éviter cette fonction.atoi()
peut être un mauvais choix dans certaines situations, parce que vous ne pouvez pas dire quand il y a une erreur de faire la conversion (par exemple, si le nombre de dépassement de la plage d'unint
). Utilisationstrtol()
si c'est important pour vous.strcpy()
,strcat()
etsprintf()
souffrent d'un problème similaire àgets()
- ils ne permettent pas de spécifier la taille de la mémoire tampon de destination. Il est toujours possible, au moins en théorie, pour une utilisation en toute sécurité - mais vous êtes beaucoup préférable d'utiliserstrncat()
etsnprintf()
à la place (vous pouvez utiliserstrncpy()
, mais voir ci-dessus). Notez que tandis que lan
poursnprintf()
est la taille de la mémoire tampon de destination, len
pourstrncat()
est le nombre maximum de caractères à ajouter et ne comprend pas le terminateur null. Une autre alternative, si vous avez déjà calculé la chaîne appropriée et la taille du buffer, estmemmove()
oumemcpy()
.Sur le même thème, si vous utilisez le
scanf()
famille de fonctions, de ne pas utiliser une plaine"%s"
- spécifier la taille de la destination, par exemple"%200s"
.fgets()
conserve le caractère de saut de ligne alors quegets()
ne le fait pas. Cela signifie que vous devez utiliser une opération telle que laif (fgets(buffer, sizeof(buffer), stdin) != NULL) { buffer[strcspn(buffer, "\n")] = '\0'; …use buffer without newline… }
. Lestrcspn()
fonction a toujours été une partie de la Norme C; il est sûr que la mémoire tampon ne ou ne contient pas un retour à la ligne (et elles ne contiennent pas un saut de ligne si la ligne est trop longue pour tenir dans la mémoire tampon, ou si le fichier est terminée sans saut de ligne).strncat()
correctement est dur. Par exemple:char dst[16] = ""; char *src = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; strncat(dst, src, sizeof(dst));
donne un dépassement de la mémoire tampon, même si vous avez utiliséstrncat()
(ou plutôt, parce que vous avez mal utiliséstrncat()
). Il écrit un octet null après la fin du tableau. Si vous en savez assez pour utiliserstrncat()
en toute sécurité, vous en savez assez pour une meilleure utilisation de solutions de rechange (memmove()
,memcpy()
, etc).fgets()
n'est pas une baisse-dans le remplacement pourgets()
. Pourstrncat()
je ne suis pas sûr que j'aurais de la caractériser à l'aide desizeof dst - 1
au lieu desizeof dst
comme "dur", mais - vous simplement devez lire la documentation et de comprendre la fonction que vous utilisez. Je suis d'accord que dans la plupart des cas lorsque vous surveiller soigneusement les longueurs des chaînes et le reste de l'espace tampon impliquer que vous finirez par vous trouvermemmove()
/memcpy()
sont la plupart des fonctions appropriées.strtok()
est généralement considéré comme le mal, car il stocke les informations d'état entre les appels. N'essayez pas de course QUE dans un environnement multithread!strtok()
. Si votre code à l'aide destrtok()
appels des fonctions, alors que c'est l'analyse avecstrtok()
, aucun de ceux que l'on appelle les fonctions peuvent utiliserstrtok()
sans vissage votre fonction. De même, aucune fonction de bibliothèque peuvent utiliserstrtok()
sans vous aviser qu'il n'parce que tout appelant qui est également à l'aide destrtok()
sera foutu. Ce sont des converse propositions, bien sûr. Donc, vous devez être extrêmement prudent si vous utilisezstrtok()
. Il est très bien pour les jouets des programmes où vous êtes en charge de l'intégralité du code; il est rarement bon pour la production de programmes de qualité.strtok_r
Strictement parlant, il est vraiment dangereux de la fonction. Il est
gets()
parce que son entrée n'est pas sous le contrôle du programmeur. Toutes les autres fonctions mentionnées ici sont sûrs d'eux-mêmes. Les "bons" et "mauvais" se résume à une programmation défensive, à savoir les préconditions, postconditions et de code réutilisable.Prenons
strcpy()
par exemple. Il a certaines conditions pour que le programmeur doit s'acquitter de avant l'appel de la fonction. Les deux chaînes doivent être valides, non pointeurs NULL à zéro des chaînes terminées, et la destination doivent fournir suffisamment d'espace avec une finale de longueur de chaîne à l'intérieur de la gamme desize_t
. En outre, les chaînes de caractères ne sont pas autorisés à se chevaucher.Qui est tout à fait beaucoup de conditions préalables, et aucun d'eux n'est vérifié par
strcpy()
. Le programmeur doit s'assurer qu'elles sont remplies, ou il doit explicitement les tester avec d'autres code réutilisable avant d'appelerstrcpy()
:Déjà silencieusement en supposant que le non-recouvrement et à zéro des chaînes terminées.
strncpy()
ne comprennent certaines de ces vérifications, mais il ajoute une autre postcondition le programmeur doit prendre soin de après l'appel de la fonction, parce que le résultat peut ne pas être égale à zéro terminée.Pourquoi ces fonctions considéré comme "mauvais"? Car ils auront besoin supplémentaire de code réutilisable pour chaque appeler pour vraiment être sur le côté sûr, lorsque le programmeur suppose tort à propos de la validité, et les programmeurs ont tendance à oublier ce code.
Ou même de s'y opposer. Prendre la
printf()
de la famille. Ces fonctions renvoient un état qui indiquent l'erreur et de succès. Qui vérifie si la sortie vers stdout ou stderr réussi? Avec l'argument que vous ne pouvez pas faire quoi que ce soit quand le standard des canaux ne sont pas de travail. Eh bien, que sur le sauvetage de données de l'utilisateur et termine le programme avec une erreur indiquant un code de sortie? Au lieu de la solution de rechange possible de crash et brûler, plus tard, de corruption des données de l'utilisateur.Dans un temps et de l'argent limitée de l'environnement, il est toujours la question de savoir combien de filets de sécurité que vous voulez vraiment et quel est le pire scénario? Si c'est un dépassement de tampon dans le cas de la str-fonctions, alors il est logique de les interdire et probablement fournir des fonctions wrapper avec les filets de sécurité déjà à l'intérieur.
Une dernière question à ce sujet: Ce qui fait de vous assurer que vos "bonnes" solutions de rechange sont vraiment bonne?
strncpy()
est concerné, ce n'est pas une "bonne" ou de la fonction de sécurité. C'est interdit par Microsoft et dans mon code.strcpy()
sont stupides; pour une chose, pourquoi ajouter de la longueur de la source; d'autre part, la vérification de la valeur NULL est inutile et trompeur code.strncpy
est conçu pour un certain vieux (pas tout à fait obsolète) format de stockage où le null de fin est omis si la chaîne correspond à peine sans elle. Pour le récupérer dans une variable de mémoire est un autrestrncpy
appel sur un autre tampon et ajouter la fuite zéro vous-même. Étant donné que les tailles ont toujours été des constantes c'étaitstrncpy(membuf, strptr->diskbuf, bufsiz)[bufsiz]
= 0; bref,strncpy
fait ce qu'il avait prévu de faire, dont vous n'avez probablement jamais besoin de le faire.strcpy()
wrapper code est incorrect. Il est de vérifier pour un hybride destrcat()
etstrcpy()
; la longueur de la condition de contrôle est incorrect pourstrcpy()
, mais la copie de code est incorrect pourstrcat()
.Une fonction qui ne prend pas en prendre un maximum de paramètres de longueur et repose plutôt sur la fin-de - marqueur à être présent (comme beaucoup de "chaîne" des fonctions de gestion).
Toute méthode qui gère l'état entre les appels.
sprintf
est mauvais, ne vérifie pas la taille, l'utilisationsnprintf
gmtime
,localtime
--use gmtime_r
,localtime_r
Pour ajouter quelque chose à propos de strncpy la plupart des gens ici, j'ai oublié de mentionner. strncpy peut entraîner des problèmes de performances qu'il efface la mémoire tampon à la longueur donnée.
copie 1 char et écraser 999 octets à 0
Une autre raison pourquoi je préfère strlcpy (je sais strlcpy est un BSDism mais il est si facile à mettre en œuvre qu'il n'y a aucune excuse pour ne pas l'utiliser).
Afficher la page 7 (PDF, page 9) SAFECode Dev Pratiques
Edit: a Partir de la page -
strcpy famille
strncpy famille
strcat famille
scanf famille
sprintf famille
obtient famille
strcpy
- nouveau!La plupart des gens conviennent que la fonction strcpy est dangereux, mais strncpy n'est que rarement utile de remplacement. Il est généralement important que vous savez quand vous avez besoin de tronquer une chaîne de caractères dans tous les cas, et pour cette raison, vous avez généralement besoin d'examiner la longueur de la chaîne source anwyay. Si c'est le cas, généralement memcpy est le meilleur remplacement que vous savez exactement combien de caractères que vous voulez copier.
par exemple, la troncature est erreur:
troncature autorisé, mais le nombre de caractères doit être retourné afin de l'appelant sait: