strncpy() schützt angeblich vor Pufferüberläufen. Aber wenn es einen Überlauf ohne Nullterminierung verhindert, wird aller Wahrscheinlichkeit nach eine nachfolgende Zeichenfolgenoperation überlaufen. Um mich dagegen zu schützen, mache ich Folgendes:
strncpy( dest, src, LEN );
dest[LEN - 1] = '\0';
man strncpy gibt:
Das strncpy() Funktion ist ähnlich, außer dass nicht mehr als n Byte von src werden kopiert. Also, wenn unter den ersten kein Null-Byte ist n Byte von srcwird 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()?
Beachten Sie, dass auf MacOS X (BSD) die Manpage sagt (von ‘extern char *strncpy(char * restrict s1, const char * restrict s2, size_t n);‘): 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 aufgefüllt. Andernfalls wird s1 nicht beendet.
– Jonathan Leffler
21. September 2009 um 21:31 Uhr
Sollte es nicht Ziel sein[LEN-1] = ‘\0’; ?
– codeObserver
18. Mai 2011 um 17:29 Uhr
So würde ich denken, dass wir eine Kopie der Zeichenfolge erstellen würden: int LEN = src.len; str* Ziel = neues Zeichen[LEN+1]; strncpy( Ziel, Quelle, LEN); Ziel[LEN] = ‘\0’;
– codeObserver
18. Mai 2011 um 17:30 Uhr
Immer Memset für Zielzeichenfolge verwenden ist der sicherste Ansatz, wenn Sie sicher sind, dass die Größe der Zeichenfolge die Länge des Zielpuffers nicht überschreitet.
– koolvcvc
4. Juli 2014 um 12:02 Uhr
Schreiben Sie Ihre eigene Funktion, ich denke nicht, dass das eine schwierige Aufgabe sein sollte
– Megharaj
30. März 2017 um 11:26 Uhr
Ernelli
strncpy() ist nicht als Safer gedacht strcpy()es soll verwendet werden, um eine Saite in die Mitte einer anderen einzufügen.
Alle diese “sicheren” String-Handling-Funktionen wie z snprintf() und vsnprintf() sind Korrekturen, die in späteren Standards hinzugefügt wurden, um Pufferüberlauf-Exploits usw.
Wikipedia erwähnt strncat() als Alternative zum Schreiben eines eigenen Safes strncpy():
*dst="\0";
strncat(dst, src, LEN);
BEARBEITEN
das habe ich vermisst strncat() überschreitet LEN Zeichen, wenn null die Zeichenfolge beendet, wenn sie länger oder gleich LEN Zeichen ist.
Wie auch immer, der Punkt der Verwendung strncat() Anstelle einer selbst entwickelten Lösung wie z memcpy(..., strlen(...))/Was ist das die Implementierung von strncat() kann in der Bibliothek ziel-/plattformoptimiert sein.
Natürlich müssen Sie überprüfen, ob dst mindestens das Nullzeichen enthält, also die korrekte Verwendung von strncat() wäre so etwas wie:
if (LEN) {
*dst="\0"; strncat(dst, src, LEN-1);
}
Das gebe ich auch zu strncpy() ist nicht sehr nützlich, um einen Teilstring in einen anderen String zu kopieren, wenn die Quelle kürzer als n Zeichen ist, wird der Zielstring abgeschnitten.
“Es soll verwendet werden, um eine Zeichenfolge in die Mitte einer anderen einzufügen” – nein, es soll eine Zeichenfolge in ein Feld mit fester Breite schreiben, z. B. in einen Verzeichniseintrag. Aus diesem Grund wird der Ausgabepuffer mit NUL aufgefüllt, wenn (und nur wenn) die Quellzeichenfolge zu kurz ist.
– Steve Jessop
21. September 2009 um 11:19 Uhr
Wie macht das Setzen von *dst=’\0′ dies sicherer? Es hat immer noch das ursprüngliche Problem, dass Sie über das Ende des Zielpuffers hinaus schreiben können.
– Adam Liss
21. September 2009 um 11:22 Uhr
klingt gut, aber sollte es nicht strncat(dst,src,LEN-1) sein, da es ein zusätzliches Zeichen schreiben wird?
– Timothy Pratley
21. September 2009 um 11:37 Uhr
@Jonathan: Eigentlich sicher wäre ein Datentyp, der einen Zeiger auf einen Zeichenpuffer mit der Länge dieses Puffers kombiniert. Aber wir alle wissen, dass das nicht passieren wird. Persönlich bin ich all dieser Bemühungen knochenmüde, etwas, das von Natur aus unsicher ist (Programmierer versuchen, die Länge eines Puffers genau zu respektieren), einen Bruchteil sicherer zu machen. Es ist nicht so, dass wir derzeit 50 % zu viele Pufferüberläufe haben, also wenn wir nur die String-Verarbeitung um 50 % sicherer machen könnten, wäre alles in Ordnung 🙁
– Steve Jessop
21. September 2009 um 12:06 Uhr
+1, um den Müll nicht zu wiederholen, dass strncpy irgendwie eine sichere Version von strcpy ist – ersteres hat seine eigenen Probleme.
– paxdiablo
12. Februar 2013 um 7:28 Uhr
Jonathan Leffler
Ursprünglich die 7. Ausgabe UNIX Dateisystem (siehe DIR(5)) hatte Verzeichniseinträge, die Dateinamen auf 14 Byte begrenzten; Jeder Eintrag in einem Verzeichnis bestand aus 2 Bytes für die Inode-Nummer plus 14 Bytes für den Namen, auf 14 Zeichen mit Null aufgefüllt, aber nicht unbedingt mit Null abgeschlossen. Das ist meine Überzeugung strncpy() wurde entwickelt, um mit diesen Verzeichnisstrukturen zu arbeiten – oder zumindest funktioniert es perfekt für diese Struktur.
In Betracht ziehen:
Ein Dateiname mit 14 Zeichen wurde nicht nullterminiert.
Wenn der Name kürzer als 14 Bytes war, wurde er mit Nullen auf die volle Länge (14 Bytes) aufgefüllt.
Genau das würde erreicht werden durch:
strncpy(inode->d_name, filename, 14);
So, strncpy() wurde ideal an seine ursprüngliche Nischenanwendung angepasst. Es ging nur zufällig darum, Überläufe von nullterminierten Strings zu verhindern.
(Beachten Sie, dass das Auffüllen mit Nullen bis zur Länge 14 kein ernsthafter Overhead ist – wenn die Länge des Puffers 4 KB beträgt und Sie nur 20 Zeichen sicher hineinkopieren möchten, dann sind die zusätzlichen 4075 Nullen ein ernsthafter Overkill und können leicht passieren zu quadratischem Verhalten führen, wenn Sie einem langen Puffer wiederholt Material hinzufügen.)
Diese spezielle Situation mag unklar sein, aber es ist nicht gerade ungewöhnlich, Datenstrukturen mit Zeichenfolgenfeldern fester Länge zu haben, die mit Nullen aufgefüllt, aber nicht mit Nullen terminiert sind. Wenn man Daten in einem festen Format speichert, ist das oft der effizienteste Weg, dies zu tun.
– Superkatze
20. November 2011 um 22:54 Uhr
Es gibt bereits Open-Source-Implementierungen wie strlcpy die sicher kopieren.
In den Literaturhinweisen befinden sich Links zu den Quellen.
Ganz zu schweigen davon, tragbar, schnell und zuverlässig. Sie können es immer noch missbrauchen, aber das Risiko ist um Größenordnungen geringer. IMO, strncpy sollte veraltet sein und durch dieselbe Funktion namens dirnamecpy oder so ähnlich ersetzt werden. strncpy ist keine sichere Zeichenfolgenkopie und war es noch nie.
– Benutzer14554
21. September 2009 um 23:38 Uhr
Liran Orevi
Strncpy ist sicherer gegen Stapelüberlaufangriffe durch die Benutzer Ihres Programms, es schützt Sie nicht vor Fehlern Sie der Programmierer, 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
Adam Liss
Einige neue Alternativen sind in ISO/IEC TR 24731 (Check https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/317-BSI.html zur Info). Die meisten dieser Funktionen verwenden einen zusätzlichen Parameter, der die maximale Länge der Zielvariablen angibt, sicherstellen, dass alle Zeichenfolgen nullterminiert sind und Namen haben, die auf enden _s (für “sicher” ?), um sie von ihren früheren “unsicheren” Versionen zu unterscheiden.1
Leider werden sie immer noch unterstützt und sind möglicherweise nicht mit Ihrem speziellen Toolset verfügbar. Spätere Versionen von Visual Studio geben Warnungen aus, wenn Sie die alten unsicheren Funktionen verwenden.
Wenn Ihre Werkzeuge nicht die neuen Funktionen unterstützen, sollte es ziemlich einfach sein, eigene Wrapper für die alten Funktionen zu erstellen. Hier ist ein Beispiel:
Sie können die Funktion an Ihre Bedürfnisse anpassen, um beispielsweise immer so viel wie möglich vom String zu kopieren, ohne dass es zu einem Überlauf kommt. Tatsächlich kann die VC++-Implementierung dies tun, wenn Sie bestehen _TRUNCATE als die count.
1Natürlich müssen Sie die Größe des Zielpuffers immer noch genau angeben: Wenn Sie einen 3-Zeichen-Puffer angeben, sagen Sie es strcpy_s() Es hat Platz für 25 Zeichen, Sie haben immer noch Probleme.
Sie können keine Funktion legal definieren, deren Name mit str * beginnt, dieser “Namespace” ist in C reserviert.
– abschalten
21. September 2009 um 11:28 Uhr
Aber das ISO C-Komitee kann es – und hat es getan. Siehe auch: stackoverflow.com/questions/372980/…
– Jonathan Leffler
21. September 2009 um 11:42 Uhr
@Jonathan: Vielen Dank für den Querverweis auf Ihre eigene Frage, die viele zusätzliche hilfreiche Informationen enthält.
Wir verwenden Makroäquivalente zu snprintf(buffer, sizeof(buffer), "%s", src). Funktioniert gut, solange Sie daran denken, es niemals für char * -Ziele zu verwenden
– che
1. Februar 2013 um 8:30 Uhr
14198100cookie-checkWarum wird strncpy nicht mit null beendet?yes
Beachten Sie, dass auf MacOS X (BSD) die Manpage sagt (von ‘
extern char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
‘): 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 aufgefüllt. Andernfalls wird s1 nicht beendet.– Jonathan Leffler
21. September 2009 um 21:31 Uhr
Sollte es nicht Ziel sein[LEN-1] = ‘\0’; ?
– codeObserver
18. Mai 2011 um 17:29 Uhr
So würde ich denken, dass wir eine Kopie der Zeichenfolge erstellen würden: int LEN = src.len; str* Ziel = neues Zeichen[LEN+1]; strncpy( Ziel, Quelle, LEN); Ziel[LEN] = ‘\0’;
– codeObserver
18. Mai 2011 um 17:30 Uhr
Immer Memset für Zielzeichenfolge verwenden ist der sicherste Ansatz, wenn Sie sicher sind, dass die Größe der Zeichenfolge die Länge des Zielpuffers nicht überschreitet.
– koolvcvc
4. Juli 2014 um 12:02 Uhr
Schreiben Sie Ihre eigene Funktion, ich denke nicht, dass das eine schwierige Aufgabe sein sollte
– Megharaj
30. März 2017 um 11:26 Uhr