Verwenden von snprintf, um Pufferüberläufe zu vermeiden

Lesezeit: 5 Minuten

Benutzeravatar von ant2009
Ameise2009

ich benutze snprintf wie folgt, um einen Pufferüberlauf zu vermeiden:

char err_msg[32] = {0};
snprintf(err_msg, sizeof(err_msg) - 1, "[ ST_ENGINE_FAILED ]");

Ich habe die hinzugefügt -1 um Platz für das Null-Terminator zu reservieren, falls die Zeichenfolge länger als 32 Bytes ist.

Liege ich mit meiner Überlegung richtig?

Plattform:

  • AGB 4.4.1
  • C99

  • Randnotiz: GCC unterstützt C99 nicht: gcc.gnu.org/c99status.html

    – Bastien Léonard

    21. November 2009 um 13:53 Uhr

  • Kennen Sie jedoch eine moderne Umgebung, in der die Kombination aus gcc und Standardbibliothek nicht enthalten ist snprintf?

    – Zum Archiv zurückgelassen

    21. November 2009 um 18:15 Uhr

  • Als ich MinGW vor ein oder zwei Jahren benutzte, hieß es tatsächlich Microsoft’s _snprintf()die sich nicht wie der Standard verhält snprintf() (Ich denke, es beendet die Zeichenfolge nicht immer mit Null).

    – Bastien Léonard

    21. November 2009 um 19:25 Uhr

Benutzeravatar von D.Shawley
D. Shawley

Wie andere gesagt haben, brauchen Sie die -1 in diesem Fall nicht. Wenn das Array eine feste Größe hat, würde ich verwenden strncpy stattdessen. Es wurde zum Kopieren von Saiten gemacht – sprintf wurde für schwierige Formatierungen entwickelt. Wenn die Größe des Arrays jedoch unbekannt ist oder Sie versuchen zu bestimmen, wie viel Speicherplatz für eine formatierte Zeichenfolge erforderlich ist. Das ist es, was ich an der Standard-spezifischen Version von wirklich mag snprintf:

char* get_error_message(char const *msg) {
    size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
    char  *buffer = malloc(needed+1);
    sprintf(buffer, "%s: %s (%d)", msg, strerror(errno), errno);
    return buffer;
}

Kombinieren Sie diese Funktion mit va_copy und Sie können sehr sicher formatierte Zeichenfolgenoperationen erstellen.

  • Verwenden Sie strncpy() nicht, wenn die Zeichenfolge möglicherweise zu groß ist, um in das Ziel zu passen. strncpy() tut es NICHT nullterminieren Sie, was es kopiert, wenn es zu lang ist. Außerdem kopiert es immer N Zeichen – selbst wenn die Quelle 1 Byte und das Ziel 1 Megabyte groß ist.

    – Jonathan Leffler

    22. November 2009 um 19:10 Uhr

  • @Jonathan: Nein. Sie haben zwar recht, dass strncpy nicht mit \0 endet tut stoppt, wenn es ein String-Endzeichen in der Quellzeichenfolge findet.

    – Nikolaus

    22. November 2009 um 21:15 Uhr

  • Dieser Code hat einen Fehler: “Nach erfolgreichem Abschluss soll die snprintf()-Funktion die Anzahl der Bytes zurückgeben, die in s geschrieben würden, wenn n ausreichend groß gewesen wäre, ausgenommen das abschließende Null-Byte.” Daher müssen Sie für die abschließende Null ein zusätzliches Byte zuweisen.

    – Jeremy Salwen

    31. August 2012 um 6:38 Uhr

  • @JeremySalwen – danke, dass du das verstanden hast … das bekomme ich für das Schreiben von Java =)

    – D. Shawley

    31. August 2012 um 16:03 Uhr

  • Könnte man einfach verwenden sprintf(buffer, …da Sie reserviert haben buffer in genau der richtigen Größe. Das würde diesen Fehler vermeiden.

    – Pascal Cuoq

    13. Juni 2014 um 17:37 Uhr

Sie brauchen die -1 nicht, wie die Referenz besagt:

Die Funktionen snprintf() und vsnprintf() schreiben nicht mehr als size Bytes (einschließlich des nachgestellten ‘\0’).

Beachten Sie den Teil “einschließlich des nachgestellten ‘\0′”.

Benutzeravatar von Alex B
Alex B

Keine Notwendigkeit für -1. C99 snprintf stets Null-terminiert. Das Größenargument gibt die Größe des Ausgabepuffers an einschließlich Null Terminator. Der Code wird somit

char err_msg[32];
int ret = snprintf(err_msg, sizeof err_msg, "[ ST_ENGINE_FAILED ]");

ret enthält die tatsächliche Anzahl der gedruckten Zeichen (ausschließlich Null-Terminator).

Allerdings nicht mit denen von Microsoft verwechseln _snprintf (vor C99), was funktioniert nicht null-terminate und hat in diesem Zusammenhang ein völlig anderes Verhalten (z. B. Rückgabe -1 anstelle der zu druckenden Länge, falls der Puffer nicht groß genug ist). Bei Verwendung _snprintfsollten Sie denselben Code wie in Ihrer Frage verwenden.

Entsprechend snprintf(3):

Die Funktionen snprintf() und vsnprintf() schreiben Sie nicht mehr als size Bytes (einschließlich der nachgestellten '\0').

Benutzeravatar von Matt Joiner
Matt Tischler

Für das angegebene Beispiel sollten Sie stattdessen Folgendes tun:

char err_msg[32];
strncpy(err_msg, "[ ST_ENGINE_FAILED ]", sizeof(err_msg));
err_msg[sizeof(err_msg) - 1] = '\0';

oder noch besser:

char err_msg[32] = "[ ST_ENGINE_FAILED ]";

  • Wie in einem Kommentar zu einer anderen Antwort erwähnt: Verwenden Sie strncpy() nicht, wenn die Zeichenfolge möglicherweise zu groß ist, um in das Ziel zu passen. strncpy() beendet das, was es kopiert, NICHT mit Null, wenn es zu lang ist. Außerdem kopiert es immer N Zeichen – selbst wenn die Quelle 1 Byte und das Ziel 1 Megabyte groß ist.

    – Jonathan Leffler

    22. November 2009 um 19:11 Uhr

  • @Jonathan Leffler, Ihre Beschreibung, wie viele Bytes strncpy() ist falsch. “Es werden höchstens n Bytes von src kopiert.” Ich habe das Beispiel angepasst, um die Null-Terminierung zu beheben.

    – Matt Tischler

    22. November 2009 um 21:07 Uhr

  • @anacrolix: Ihr Beispiel garantiert keine NULL-Beendigung. Das garantiert es strncpy() wird niemals das letzte Zeichen im Puffer überschreiben. Das müssen Sie ausdrücklich tun err_msg[sizeof(err_msg)-1] = '\0'; Kündigung zu bekommen.

    – D. Shawley

    11. Dezember 2009 um 12:20 Uhr

Benutzeravatar von TheGrandWazoo
TheGrandWazoo

sizeof gibt die Anzahl der Bytes zurück, die der Datentyp im Speicher verwendet, nicht die Länge der Zeichenfolge. ZB sizeof(int) gibt ‘4’ Bytes auf einem 32-Bit-System zurück (na ja, abhängig von der Implementierung, denke ich). Da Sie in Ihrem Array eine Konstante verwenden, können Sie diese problemlos an printf übergeben.

  • Wie in einem Kommentar zu einer anderen Antwort erwähnt: Verwenden Sie strncpy() nicht, wenn die Zeichenfolge möglicherweise zu groß ist, um in das Ziel zu passen. strncpy() beendet das, was es kopiert, NICHT mit Null, wenn es zu lang ist. Außerdem kopiert es immer N Zeichen – selbst wenn die Quelle 1 Byte und das Ziel 1 Megabyte groß ist.

    – Jonathan Leffler

    22. November 2009 um 19:11 Uhr

  • @Jonathan Leffler, Ihre Beschreibung, wie viele Bytes strncpy() ist falsch. “Es werden höchstens n Bytes von src kopiert.” Ich habe das Beispiel angepasst, um die Null-Terminierung zu beheben.

    – Matt Tischler

    22. November 2009 um 21:07 Uhr

  • @anacrolix: Ihr Beispiel garantiert keine NULL-Beendigung. Das garantiert es strncpy() wird niemals das letzte Zeichen im Puffer überschreiben. Das müssen Sie ausdrücklich tun err_msg[sizeof(err_msg)-1] = '\0'; Kündigung zu bekommen.

    – D. Shawley

    11. Dezember 2009 um 12:20 Uhr

1433430cookie-checkVerwenden von snprintf, um Pufferüberläufe zu vermeiden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy