web-dev-qa-db-fra.com

Existe-t-il une version sûre de strlen?

std :: strlen ne gère pas les chaînes c qui ne sont pas\0 terminées. Existe-t-il une version sécurisée?

PS Je sais que dans c ++, std :: string devrait être utilisé à la place de c, mais dans ce cas, ma chaîne est stockée dans une mémoire partagée.

EDIT

Ok, je dois ajouter une explication.

Mon application obtient une chaîne d'une mémoire partagée (qui a une certaine longueur), elle pourrait donc être représentée par un tableau de caractères. S'il y a un bogue dans la bibliothèque en train d'écrire cette chaîne, celle-ci ne serait pas terminée à zéro, et strlen pourrait échouer.

22
BЈовић

Si vous définissez une c-chaîne comme 

char* cowSays = "moo";

alors vous obtenez automatiquement le '\ 0' à la fin et strlen renverra 3. Si vous le définissez comme:

char iDoThis[1024] = {0};

vous obtenez un tampon vide (et un tableau de caractères, qui sont tous des caractères nuls). Vous pouvez ensuite le remplir avec ce que vous voulez tant que vous ne dépassez pas la longueur de la mémoire tampon. Au début, strlen renvoie 0, et une fois que vous avez écrit quelque chose, vous obtenez également le nombre correct de strlen.
Vous pouvez aussi faire ceci:

char uhoh[100];
int len = strlen(uhoh);

mais ce serait dommage, car vous n’avez aucune idée de ce qui se trouve dans cet ensemble. Il pourrait frapper un caractère nul que vous ne pourriez pas. Le fait est que le caractère nul est le norme définie manière à déclarer que la chaîne est terminée.
Ne pas avoir un caractère nul signifie par définition que la chaîne n'est pas finie. Changer cela briserait le paradigme du fonctionnement de la chaîne. Ce que vous voulez faire, c'est créer vos propres règles. C++ vous permettra de le faire, mais vous devrez écrire beaucoup de code vous-même.

MODIFIER À partir des informations que vous avez ajoutées récemment, vous souhaitez effectuer une boucle sur le tableau et rechercher manuellement le caractère nul. Vous devez également procéder à une validation si vous attendez des caractères ASCII uniquement (surtout si vous attendez des caractères alphanumériques). Cela suppose que vous connaissiez la taille maximale. Si vous n'avez pas besoin de valider le contenu de la chaîne, vous pouvez utiliser l'une des familles strnlen de: http: // msdn .Microsoft.com/fr-fr/library/z50ty2zh% 28v = vs.80% 29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm

7
Dennis

Vous avez ajouté que la chaîne est en mémoire partagée. C'est garanti lisible et de taille fixe. Vous pouvez donc utiliser size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize) (attention à la n supplémentaire dans strnlen). 

Ceci renverra MaxPossibleSize s'il n'y a pas \0 dans la mémoire partagée après input, ou la longueur de la chaîne s'il en existe une. (La longueur de chaîne maximale possible est bien sûr MaxPossibleSize-1, dans le cas où le dernier octet de mémoire partagée est le premier \0)

15
MSalters

Les chaînes C non terminées par un caractère null ne sont pas des chaînes C, ce sont simplement des tableaux de caractères et il n'existe aucun moyen de déterminer leur longueur.

12
size_t safe_strlen(const char *str, size_t max_len)
{
    const char * end = (const char *)memchr(str, '\0', max_len);
    if (end == NULL)
        return max_len;
    else
        return end - str;
}
6
Andrew W. Phillips

Obtenez une meilleure bibliothèque, ou vérifiez celle que vous avez - si vous ne pouvez pas faire confiance à votre bibliothèque pour faire ce qu'elle dit, alors comment attendez-vous votre programme? 

Cela dit, en supposant que vous connaissiez la longueur du buiffer la chaîne réside, qu'en est-il 

buffer[-1+sizeof(buffer)]=0 ;
 x = strlen(buffer) ; 
  • faire tampon plus grand que nécessaire et vous pouvez alors tester la lib.

    assert(x<-1+sizeof(buffer));
    
3
mattnz

Si vous devez obtenir la taille de la mémoire partagée, essayez d’utiliser

// get memory size
struct shmid_ds shm_info;
size_t shm_size;
int shm_rc;
if((shm_rc = shmctl(shmid, IPC_STAT, &shm_info)) < 0)
    exit(101);
shm_size = shm_info.shm_segsz;

Au lieu d'utiliser strlen, vous pouvez utiliser shm_size - 1 si vous êtes sûr qu'il est terminé avec null. Sinon, vous pouvez le terminer NULL par data [shm_size - 1] = '\ 0'; puis utilisez strlen (data);

0
edo888

Vous devrez encoder votre chaîne. Par exemple:

struct string
{
    size_t len;
    char *data;
} __attribute__(packed);

Vous pouvez ensuite accepter n'importe quel tableau de caractères si vous savez que le premier octet sizeof (size_t) de l'emplacement de mémoire partagée correspond à la taille du tableau de caractères. Cela devient délicat lorsque vous souhaitez chaîner des tableaux de cette façon.

Il vaut mieux faire confiance à votre autre extrémité pour terminer ses chaînes ou lancer votre propre chaîne qui ne sort pas des limites du segment de mémoire partagée (à condition de connaître au moins la taille de ce segment).

0
Mel

une solution simple:

buff[BUFF_SIZE -1] = '\0'

ofc cela ne vous dira pas si la chaîne à l'origine était exactement BUFF_SIZE-1 longue ou si elle n'était tout simplement pas terminée ... vous avez donc besoin de la logique xtra pour cela. 

0
NoSenseEtAl

Que diriez-vous de cette pépite portable:

int safeStrlen(char *buf, int max)
{
   int i;
   for(i=0;buf[i] && i<max; i++){};
   return i;
}
0
hotplasma

Comme Neil Butterworth déjà dit dans sa réponse ci-dessus: Les C-Strings qui ne se terminent pas par un caractère\0 ne sont pas des C-Strings! 

La seule chance que vous ayez est d'écrire un adaptateur immuable ou quelque chose qui crée une copie valide de la chaîne de caractères avec un caractère de fin\0. Bien sûr, si l'entrée est fausse et qu'il existe une chaîne de caractères définie comme:

char cstring[3] = {'1','2','3'};

entraînera un comportement inattendu, car il peut y avoir quelque chose comme 123@4x\0 dans la mémoire maintenant. Ainsi, le résultat de strlen () par exemple est maintenant 6 et non 3 comme prévu.

L'approche suivante montre comment créer un C-String sécurisé dans tous les cas:

char *createSafeCString(char cStringToCheck[]) {
    //Cast size_t to integer
    int size = static_cast<int>(strlen(cStringToCheck)) ;
    //Initialize new array out of the stack of the method
    char *pszCString = new char[size + 1];
    //Copy data from one char array to the new
    strncpy(pszCString, cStringToCheck, size);
    //set last character to the \0 termination character
    pszCString[size] = '\0';
    return pszCString;
}

Cela garantit que si vous manipulez le C-String pour ne pas écrire sur la mémoire de quelque chose d'autre.

Mais ce n'est pas ce que tu voulais. Je sais, mais il n’ya pas d’autre moyen de réaliser la longueur d’un tableau de caractères sans interruption. Ce n'est même pas une approche. Cela garantit simplement que même si l'utilisateur (ou le développeur) insère ***** pour fonctionner correctement.

0
Code.IT