flawopen.com/Speichersicherheit/strcpy vs strncpy
Ist strncpy() sicherer als strcpy()?
Ein Feld mit fester Breite ist wie eine Reihe markierter Plätze: Der letzte braucht ein Endzeichen, wenn der Code die Bytes als C-String behandelt. strncpy() schreibt höchstens n Bytes und verhindert einen Überlauf nur, wenn n nicht größer als der echte Puffer ist. Füllt die Quelle dieses Limit aus, hängt die Funktion keinen Nullterminator an. Eine spätere Stringfunktion kann dann über das Ziel hinaus nach dem fehlenden Zeichen lesen.
char dst[16]; /* 1. Unbounded — classic overflow */ strcpy(dst, src); /* 2. Bounded, but may not terminate. If strlen(src) >= 16, dst has no '\0' and every later strlen/printf reads out of bounds. */ strncpy(dst, src, sizeof(dst)); /* 3. Off-by-one: room for 16 chars plus a terminator = 17 bytes, but dst only holds 16. */ strncpy(dst, src, sizeof(dst)); dst[sizeof(dst)] = '\0'; /* OOB! */
char dst[16]; /* Preferred: snprintf always null-terminates (when size > 0), and tells you about truncation. */ int n = snprintf(dst, sizeof(dst), "%s", src); if (n < 0 || (size_t)n >= sizeof(dst)) { /* truncated — handle it */ return ERR_TOO_LONG; } /* Or strlcpy where available — always terminates, returns the length it tried to create. */ if (strlcpy(dst, src, sizeof(dst)) >= sizeof(dst)) { return ERR_TOO_LONG; }
Wofür strncpy ursprünglich gedacht war
Das Verhalten ist kein Fehler: strncpy() wurde für Felder fester Breite mit Nullauffüllung entwickelt, nicht als allgemein sichere C-String-Kopie. Ist der Quellstring kürzer als n, füllt die Funktion das Ziel bis Byte n - 1 mit Nullbytes auf. Gibt es in den ersten n Quellbytes kein Nullbyte, kopiert sie genau n Bytes und terminiert das Ziel nicht. Das passt zu manchen Festfeldformaten, ist aber gefährlich für APIs, die einen nullterminierten String erwarten.
Bei einer Quelle kürzer als n schreibt die nötige Auffüllung bis zur gesamten Feldbreite. Bei großem Ziel und kurzer Quelle kann das mehr Arbeit verursachen als eine Kopie, die am Terminator stoppt.
Trunkierung immer prüfen
Einen Überlauf zu verhindern ist nur die halbe Aufgabe. Stille Trunkierung ist ebenfalls riskant: Ein gekürzter Hostname, Pfad oder Autorisierungswert kann seine Bedeutung ändern. snprintf gibt die Länge zurück, die es schreiben wollte; vergleiche sie mit der Puffergröße. Die Fehlinterpretation als tatsächlich geschriebene Bytes spielte auch bei Citrix Bleed eine Rolle.
Häufige Fragen
Sie terminieren und prüfen Grenzen, sind aber unterschiedlich portabel: unter Windows gut unterstützt, andernorts uneinheitlich implementiert. Für mehrere Plattformen ist snprintf meist besser verfügbar.
Nein. Die Funktion stammt aus OpenBSD und ist auf BSD und macOS verfügbar; neuere glibc-Versionen enthalten sie ebenfalls. Prüfe die Verfügbarkeit für deine Zielsysteme.
Bevorzuge std::string und std::string_view, die Längen verwalten. C-Funktionen gehören an API-Grenzen, die rohe Puffer verlangen.