strncpy()
schützt angeblich vor Pufferüberläufen. Wenn jedoch ein Überlauf ohne Nullbeendigung verhindert wird, wird aller Wahrscheinlichkeit nach eine nachfolgende Zeichenfolgenoperation überlaufen. Um mich davor zu schützen, mache ich Folgendes:
strncpy( dest, src, LEN );
dest[LEN - 1] = '\0';
man strncpy
gibt:
Die
strncpy()
Funktion ist ähnlich, außer dass nicht mehr alsn
Bytes vonsrc
kopiert werden. Wenn also kein Nullbyte unter den erstenn
Bytes von vorhanden istsrc
, wird das Ergebnis nicht nullterminiert.
Ohne null etwas scheinbar Unschuldiges zu beenden wie:
printf( "FOO: %s\n", dest );
... könnte abstürzen.
Gibt es bessere und sicherere Alternativen zu strncpy()
?
extern char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
') steht: Die Funktion strncpy () kopiert höchstens n Zeichen von s2 nach s1. Wenn s2 weniger als n Zeichen lang ist, wird der Rest von s1 mit "\ 0" Zeichen gefüllt. Andernfalls wird s1 nicht beendet.Antworten:
strncpy()
ist nicht als sicherer gedachtstrcpy()
, sondern soll verwendet werden, um eine Zeichenfolge in die Mitte einer anderen einzufügen.Alle diese "sicheren" Zeichenfolgenbehandlungsfunktionen wie
snprintf()
undvsnprintf()
sind Korrekturen, die in späteren Standards hinzugefügt wurden, um Pufferüberlauf-Exploits usw. zu verringern.Wikipedia erwähnt
strncat()
als Alternative zum Schreiben Ihres eigenen Safesstrncpy()
:*dst = '\0'; strncat(dst, src, LEN);
BEARBEITEN
Ich habe übersehen, dass
strncat()
LEN-Zeichen überschritten werden, wenn die Zeichenfolge mit Null beendet wird, wenn sie länger oder gleich LEN-Zeichen ist.Wie auch immer, der Sinn der Verwendung
strncat()
anstelle einer selbst entwickelten Lösung wiememcpy(..., strlen(...))
/ was auch immer ist, dass die Implementierung vonstrncat()
Ziel / Plattform in der Bibliothek optimiert sein könnte.Natürlich müssen Sie überprüfen, ob dst mindestens das Nullzeichen enthält, damit die korrekte Verwendung von ungefähr so lautet
strncat()
:if (LEN) { *dst = '\0'; strncat(dst, src, LEN-1); }
Ich gebe auch zu, dass dies
strncpy()
nicht sehr nützlich ist, um einen Teilstring in einen anderen String zu kopieren. Wenn der src kürzer als n Zeichen ist, wird der Zielstring abgeschnitten.quelle
Ursprünglich hatte das UNIX- Dateisystem der 7. Edition (siehe DIR (5)) Verzeichniseinträge, die die Dateinamen auf 14 Byte beschränkten. Jeder Eintrag in einem Verzeichnis bestand aus 2 Bytes für die Inode-Nummer plus 14 Bytes für den Namen, null auf 14 Zeichen aufgefüllt, aber nicht unbedingt nullterminiert. Ich bin davon überzeugt, dass
strncpy()
es für diese Verzeichnisstrukturen entwickelt wurde - oder zumindest perfekt für diese Struktur.Erwägen:
Dies ist genau das, was erreicht werden würde durch:
strncpy(inode->d_name, filename, 14);
So
strncpy()
wurde ideal zu seiner ursprünglichen Nischenanwendung angepasst. Es ging nur zufällig darum, Überläufe von nullterminierten Zeichenfolgen zu verhindern.(Beachten Sie, dass das Auffüllen von Nullen bis zur Länge 14 kein schwerwiegender Aufwand ist. Wenn die Länge des Puffers 4 KB beträgt und Sie nur 20 Zeichen sicher in den Puffer kopieren möchten, sind die zusätzlichen 4075-Nullen ein schwerwiegender Overkill und können leicht auftreten führen zu quadratischem Verhalten, wenn Sie wiederholt Material zu einem langen Puffer hinzufügen.)
quelle
Es gibt bereits Open Source-Implementierungen wie strlcpy , die sicher kopieren.
http://en.wikipedia.org/wiki/Strlcpy
In den Referenzen gibt es Links zu den Quellen.
quelle
Strncpy ist sicherer gegen Stapelüberlaufangriffe durch den Benutzer Ihres Programms. Es schützt Sie nicht vor Fehlern , die der Programmierer macht, wie z. B. das Drucken einer nicht nullterminierten Zeichenfolge, wie Sie es beschrieben haben.
Sie können einen Absturz aufgrund des von Ihnen beschriebenen Problems vermeiden, indem Sie die Anzahl der von printf gedruckten Zeichen begrenzen:
char my_string[10]; //other code here printf("%.9s",my_string); //limit the number of chars to be printed to 9
quelle
%s
muss eines der dunkelsten Merkmale von C. seinEinige neue Alternativen sind in ISO / IEC TR 24731 angegeben ( Informationen finden Sie unter https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/317-BSI.html ). Die meisten dieser Funktionen verwenden einen zusätzlichen Parameter, der die maximale Länge der Zielvariablen angibt, sicherstellt, dass alle Zeichenfolgen nullterminiert sind und Namen haben, die auf
_s
(für "sicher"?) Enden , um sie von ihren früheren "unsicheren" Versionen zu unterscheiden . 1Leider erhalten sie immer noch Unterstützung und sind möglicherweise nicht mit Ihrem speziellen Tool-Set verfügbar. In späteren Versionen von Visual Studio werden Warnungen ausgegeben, wenn Sie die alten unsicheren Funktionen verwenden.
Wenn Ihre Tools die neuen Funktionen nicht unterstützen, sollte es ziemlich einfach sein, eigene Wrapper für die alten Funktionen zu erstellen. Hier ist ein Beispiel:
errCode_t strncpy_safe(char *sDst, size_t lenDst, const char *sSrc, size_t count) { // No NULLs allowed. if (sDst == NULL || sSrc == NULL) return ERR_INVALID_ARGUMENT; // Validate buffer space. if (count >= lenDst) return ERR_BUFFER_OVERFLOW; // Copy and always null-terminate memcpy(sDst, sSrc, count); *(sDst + count) = '\0'; return OK; }
Sie können die Funktion an Ihre Bedürfnisse anpassen, um beispielsweise immer so viel wie möglich von der Zeichenfolge zu kopieren, ohne überzulaufen. Tatsächlich kann die VC ++ - Implementierung dies tun, wenn Sie
_TRUNCATE
als übergebencount
.1 Natürlich müssen Sie die Größe des Zielpuffers genau bestimmen: Wenn Sie einen 3-Zeichen-Puffer
strcpy_s()
angeben, aber angeben, dass er Platz für 25 Zeichen bietet, sind Sie immer noch in Schwierigkeiten.quelle
Verwendung
strlcpy()
, hier angegeben:http://www.courtesan.com/todd/papers/strlcpy.htmlWenn Ihre libc keine Implementierung hat, versuchen Sie diese:
size_t strlcpy(char* dst, const char* src, size_t bufsize) { size_t srclen =strlen(src); size_t result =srclen; /* Result is always the length of the src string */ if(bufsize>0) { if(srclen>=bufsize) srclen=bufsize-1; if(srclen>0) memcpy(dst,src,srclen); dst[srclen]='\0'; } return result; }
(Geschrieben von mir im Jahr 2004 - für den öffentlichen Bereich gewidmet.)
quelle
srclen
besser, da wir wissen würden, wie viele Zeichen wirklich kopiert werden.strncpy arbeitet direkt mit den verfügbaren Zeichenfolgenpuffern. Wenn Sie direkt mit Ihrem Speicher arbeiten, MÜSSEN Sie jetzt die Größe puffern und Sie können die '\ 0' manuell einstellen.
Ich glaube, es gibt keine bessere Alternative in C, aber es ist nicht wirklich so schlimm, wenn Sie so vorsichtig sind, wie Sie es sollten, wenn Sie mit rohem Gedächtnis spielen.
quelle
Stattdessen
strncpy()
könnten Sie verwendensnprintf(buffer, BUFFER_SIZE, "%s", src);
Hier ist ein Einzeiler, der höchstens
size-1
Nicht-Null-Zeichen vonsrc
bis kopiertdest
und einen Null-Terminator hinzufügt:static inline void cpystr(char *dest, const char *src, size_t size) { if(size) while((*dest++ = --size ? *src++ : 0)); }
quelle
snprintf(buffer, sizeof(buffer), "%s", src)
. Funktioniert gut, solange du nie daran erinnern verwenden , um auf char * ZieleIch habe es immer vorgezogen:
memset(dest, 0, LEN); strncpy(dest, src, LEN - 1);
um das Problem danach zu beheben, aber das ist wirklich nur eine Frage der Präferenz.
quelle
dest[LEN-1]
auf0
- die anderen Bytes werden bei Bedarf mit gefülltstrncpy()
(denken Sie daran:strncpy(s,d,n)
schreibt IMMERn
Bytes!)Diese Funktionen haben sich mehr entwickelt als entworfen, daher gibt es wirklich kein "Warum". Sie müssen nur lernen, "wie". Leider enthalten die Linux-Manpages zumindest keine allgemeinen Anwendungsbeispiele für diese Funktionen, und ich habe in dem von mir überprüften Code viele Missbräuche festgestellt . Ich habe hier einige Notizen gemacht: http://www.pixelbeat.org/programming/gcc/string_buffers.html
quelle
strncpy()
es vorhanden ist, kann man die Nullterminierung erzwingen, indem man manuell ein Nullbyte am Ende des Puffers schreibt. Wenn strncpy () darauf bestand, immer ein Null-Byte nach dem letzten nützlichen Speicherort zu schreiben, kann ich mir keine effiziente Methode zum Aktualisieren von null-aufgefüllten (nicht terminierten) Zeichenfolgen vorstellen. Beachten Sie, dass mit Nullen aufgefüllte Zeichenfolgen mit bekannter fester Länge ein zeiteffizientes Mittel zum Speichern von Daten auf der Festplatte waren und sind. Das Speichern von Informationen im RAM im selben Format wie auf der Festplatte kann ebenfalls die Leistung steigern.Ohne mich auf neuere Erweiterungen zu verlassen, habe ich in der Vergangenheit so etwas getan:
/* copy N "visible" chars, adding a null in the position just beyond them */ #define MSTRNCPY( dst, src, len) ( strncpy( (dst), (src), (len)), (dst)[ (len) ] = '\0')
und vielleicht sogar:
/* pull up to size - 1 "visible" characters into a fixed size buffer of known size */ #define MFBCPY( dst, src) MSTRNCPY( (dst), (src), sizeof( dst) - 1)
Warum funktionieren die Makros anstelle neuerer "eingebauter" (?) Funktionen? Weil es früher einige verschiedene Unices gab, sowie andere Nicht-Unix-Umgebungen (Nicht-Windows-Umgebungen), auf die ich portieren musste, wenn ich täglich C machte.
quelle