it-swarm.com.de

Gibt es eine sichere Version von strlen?

std :: strlen verarbeitet keine c-Zeichenfolgen, die nicht mit\0 abgeschlossen sind. Gibt es eine sichere Version davon?

PS Ich weiß, dass in c ++ std :: string anstelle von c-Strings verwendet werden sollte, aber in diesem Fall ist mein String in einem gemeinsamen Speicher abgelegt.

EDIT

Ok, ich muss eine Erklärung hinzufügen.

Meine Anwendung erhält eine Zeichenfolge aus einem gemeinsam genutzten Speicher (der eine gewisse Länge hat), daher könnte sie als Array von Zeichen dargestellt werden. Wenn in der Bibliothek ein Fehler auftritt, der diese Zeichenfolge schreibt, wird die Zeichenfolge nicht mit Null beendet, und die Zeichenfolge kann fehlschlagen.

22
BЈовић

Wenn Sie einen C-String als definieren 

char* cowSays = "moo";

dann erhalten Sie automatisch das '\ 0' am Ende und strlen würde 3 zurückgeben. Wenn Sie es wie folgt definieren:

char iDoThis[1024] = {0};

sie erhalten einen leeren Puffer (und ein Array von Zeichen, die alle Nullzeichen sind). Sie können es dann mit dem füllen, was Sie möchten, solange Sie die Pufferlänge nicht überschreiten. Am Anfang würde strlen 0 zurückgeben, und wenn Sie etwas geschrieben haben, erhalten Sie auch die korrekte Nummer von strlen.
Sie könnten dies auch tun:

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

das wäre aber schlecht, weil Sie keine Ahnung haben, was sich in diesem Array befindet. Es könnte ein Nullzeichen sein, das Sie möglicherweise nicht treffen. Der Punkt ist, dass das Nullzeichen das ist definierter Standard So können Sie feststellen, dass die Zeichenfolge abgeschlossen ist.
Kein Nullzeichen bedeutet per Definition dass der String nicht fertig ist. Wenn Sie das ändern, wird das Paradigma der Funktionsweise der Zeichenfolge gebrochen. Sie möchten Ihre eigenen Regeln aufstellen. C++ lässt Sie das tun, aber Sie müssen selbst viel Code schreiben.

BEARBEITEN Von den neu hinzugefügten Informationen wollen Sie das Array durchlaufen lassen und das Nullzeichen von Hand prüfen. Sie sollten auch einige Überprüfungen durchführen, wenn Sie nur ASCII -Zeichen erwarten (insbesondere wenn Sie alphanumerische Zeichen erwarten). Dies setzt voraus, dass Sie die maximale Größe kennen. Wenn Sie den Inhalt der Zeichenfolge nicht überprüfen müssen, können Sie eine der strnlen-Funktionsfamilien verwenden: http: // msdn .Microsoft.com/de-de/library/z50ty2zh% 28v = vs.80% 29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm

7
Dennis

Sie haben hinzugefügt, dass sich die Zeichenfolge im Shared Memory befindet. Das ist garantiert lesbar und von fester Größe. Sie können daher size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize) verwenden (beachten Sie die zusätzliche n in strnlen). 

Dies gibt MaxPossibleSize zurück, wenn nach input kein \0 im gemeinsam genutzten Speicher vorhanden ist, oder die Zeichenfolgenlänge, falls vorhanden. (Die maximal mögliche Stringlänge ist natürlich MaxPossibleSize-1, falls das letzte Byte des Shared Memory das erste \0 ist)

15
MSalters

C-Strings, die nicht nullterminiert sind, sind keine C-Strings. Sie sind einfach Arrays von Zeichen und es gibt keine Möglichkeit, ihre Länge zu ermitteln.

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

Besorgen Sie sich eine bessere Bibliothek, oder überprüfen Sie diejenige, die Sie haben - wenn Sie nicht darauf vertrauen können, dass Ihre Bibliothek das tut, was sie sagt, wie wird es aussehen? Wie erwarten Sie Ihr Programm? 

Das heißt, vorausgesetzt, Sie wissen, wie lang die Saite ist, was ist die Saite? 

buffer[-1+sizeof(buffer)]=0 ;
 x = strlen(buffer) ; 
  • buffer größer machen als benötigt und Sie können die lib testen.

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

Wenn Sie die Größe des gemeinsam genutzten Speichers benötigen, versuchen Sie es mit

// 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;

Anstelle von strlen können Sie shm_size-1 verwenden, wenn Sie sich sicher sind, dass es null ist. Andernfalls können Sie ihn mit data null beenden [shm_size - 1] = '\ 0'; dann verwenden Sie strlen (Daten);

0
edo888

Sie müssen Ihre Zeichenfolge kodieren. Zum Beispiel:

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

Sie können dann ein beliebiges Array von Zeichen akzeptieren, wenn Sie wissen, dass die ersten Bytes (size_t) des Speicherplatzes im gemeinsam genutzten Speicher die Größe des Char-Arrays sind. Es wird schwierig, wenn Sie Arrays auf diese Weise verketten möchten.

Es ist besser, darauf zu vertrauen, dass das andere Ende seine Zeichenfolgen beendet, oder dass Sie Ihre eigenen Zeichenfolgen rollen, die nicht über die Grenzen des gemeinsam genutzten Speichersegments hinausgehen (vorausgesetzt, Sie kennen zumindest die Größe dieses Segments).

0
Mel

eine einfache Lösung:

buff[BUFF_SIZE -1] = '\0'

ofc Dies sagt Ihnen nicht, ob der String ursprünglich genau BUFF_SIZE-1 lang war oder ob er nicht gerade beendet wurde ... Sie benötigen dafür xtra logic. 

0
NoSenseEtAl

Wie wäre es mit diesem tragbaren Nugget:

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

Wie Neil Butterworth schon in seiner Antwort oben gesagt: C-Strings, die nicht mit einem\0-Zeichen abgeschlossen sind, sind keine C-Strings! 

Die einzige Möglichkeit besteht darin, einen unveränderlichen Adapter zu schreiben oder etwas, das eine gültige Kopie des C-Strings mit einem\0-Abschlusszeichen erstellt. Wenn die Eingabe falsch ist und es einen C-String gibt, der wie folgt definiert ist:

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

führt in der Tat zu unerwartetem Verhalten, da sich jetzt etwas wie [email protected]\0 im Speicher befinden kann. Das Ergebnis von strlen () ist zum Beispiel jetzt 6 und nicht wie erwartet 3.

Der folgende Ansatz zeigt, wie in jedem Fall ein sicherer C-String erstellt wird:

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;
}

Dadurch wird sichergestellt, dass der C-String so manipuliert wird, dass er nicht in den Speicher von etwas anderem schreibt.

Aber das wollten Sie nicht. Ich weiß, aber es gibt keinen anderen Weg, um die Länge eines Char-Arrays ohne Terminierung zu erreichen. Dies ist nicht einmal ein Ansatz. Es stellt nur sicher, dass selbst wenn der Benutzer (oder Dev) ***** einfügt, einwandfrei funktioniert.

0
Code.IT