web-dev-qa-db-fra.com

Pourquoi est-on considéré comme dangereux?

Quelle (s) caractéristique (s) de strtok est dangereuse (en termes de débordement de mémoire tampon) que je dois surveiller?

Ce qui est un peu étrange pour moi, c’est que strtok_s (qui est "sûr") dans Visual C++ possède un paramètre "contexte" supplémentaire, mais il semble que ce soit la même chose à d’autres égards ... est-il identique ou est-il vraiment différent ?

25
Mehrdad

Selon la section strtok_s de ce document :

6.7.3.1 La fonction strtok_s La fonction strtok_s résout deux problèmes dans la fonction strtok:

  1. Un nouveau paramètre, s1max, empêche strtok_s de stocker en dehors de la chaîne sous marque. (La chaîne divisée en jetons est à la fois une entrée et une sortie de la fonction puisque strtok_s stocke des caractères nuls dans la chaîne.)
  2. Un nouveau paramètre, ptr, élimine l'état interne statique qui empêche strtok d'être réentrant (sous-paragraphe 1.1.12). (La fonction wcstok ISO/IEC 9899 et la fonction strtok_r ISO/IEC 9945 (POSIX) résolvent ce problème à l'identique.)
24
Heisenbug

Il n'y a rien de dangereux à ce sujet. Vous avez juste besoin de comprendre comment cela fonctionne et comment l'utiliser. Une fois que vous avez écrit votre code et le test unitaire, il ne faut que quelques minutes supplémentaires pour relancer le test unitaire avec valgrind afin de vous assurer que vous utilisez bien les limites de la mémoire. La page de manuel dit tout:

BOGUES

Soyez prudent lorsque vous utilisez ces fonctions. Si vous les utilisez, notez que:

  • Ces fonctions modifient leur premier argument.
  • Ces fonctions ne peuvent pas être utilisées sur des chaînes constantes.
  • L'identité du caractère de délimitation est perdue.
  • La fonction strtok() utilise un tampon statique lors de l'analyse, elle n'est donc pas thread-safe. Utilisez strtok_r() si cela vous concerne.
11
Bob

strtok est sécurisé dans Visual C++ (mais nulle part ailleurs), car il utilise le stockage local du thread pour enregistrer son état entre les appels. Partout ailleurs, la variable globale est utilisée pour sauvegarder l'état strtok ().

Cependant, même dans VC++, où strtok est thread-safe, cela reste un peu bizarre - vous ne pouvez pas utiliser strtok () s sur différentes chaînes du même thread en même temps. Par exemple, cela ne fonctionnerait pas bien:

     token = strtok( string, seps );
     while(token)
     {
        printf("token=%s\n", token)
        token2 = strtok(string2, seps);
        while(token2)  
        {
            printf("token2=%s", token2);
            token2 = strtok( NULL, seps );
        }
        token = strtok( NULL, seps );
     }

La raison pour laquelle cela ne fonctionnerait pas bien - pour chaque thread, seul un état peut être sauvegardé dans le stockage local du thread. Dans ce cas, il faudrait 2 états - pour la première chaîne et pour la seconde. Ainsi, bien que strtok soit thread-safe avec VC++, il n’est pas réentrant.

Ce que strtok_s (ou strtok_r partout ailleurs) fournit - un état explicite et avec lequel strtok devient réentrant.

4

Si vous n'avez pas de chaîne correctement terminée par un caractère null; vous allez vous retrouver dans un buffer overflow. Notez également (c’est quelque chose que j’ai appris à la dure) que strtok ne semble pas se soucier des chaînes internes. C'EST À DIRE. avoir "bonjour"/"monde" analysera "bonjour"/"monde" alors que "bonjour/monde" analysera "bonjour monde". Notez qu'il se scinde sur le/et ignore le fait qu'il se trouve entre parenthèses.

0
Suroot