Frage zum Pufferüberlauf



  • Kann mir mal jemand folgenden Abschnitt erklären?
    https://de.wikipedia.org/w/index.php?title=Pufferüberlauf&stable=0&shownotice=1&fromsection=Prozessoren_und_Programmierstil#Beispiel

    Darin heißt es:

    Da strcpy() die Größen von Quelle und Ziel nicht überprüft, sondern als Quelle einen null-terminierten ('\0') Speicherbereich erwartet, ist auch die folgende Variante unsicher (sie wird allerdings nicht über "buf" hinausschießen, sondern ggf. über das Ende des "s" zugewiesenen Speicherbereichs).

    char * buf;
    
    buf = malloc(1 + strlen(s)); // Plus 1 wegen des terminierenden NUL-Zeichens
    if (buf)
        strcpy(buf, s);
    

    Das mit dem "buf nicht hinausschießen", habe ich verstanden, aber inwiefern ist das trotzdem unsicher?

    buf wird ja genau so groß, dass s und 1 Byte für das Nullzeichen hineinpasst.
    s passt also immer in buf.
    Genauso kann man immer ein Nullzeichen anfügen.

    Bleibt also nur der Fall, das s mal kein Nullzeichen haben sollte, dann wird nie eines angefügt, sofern es nicht manuell geschieht und später im Programmcode könnte das dann vielleicht mal zu einem Problem werden, aber warum sollte s kein Nullzeichen haben?

    Zumal der Code ja leicht mit buf[strlen(buf)-1] = '\0'; erweiterbar wäre, so dass immer garantiert ist, dass er immer ein Nullzeichen hat.

    Zudem stellt sich ja auch die Frage, wenn s kein Nullzeichen haben sollte, warum sollte dann strlen(s) richtig funktionieren?


  • Mod

    Es geht um fehlende Nullterminierung von s. Und ja, dann ist bereits das strlen ein Problem. Aber man ist sowieso in großen Schwierigkeiten, wenn s die Grundannahme verletzt, dass es nullterminiert sein sollte. Das heißt, dann muss schon vorher im Programm ein Fehler vorliegen. Die Argumentation hier soll wohl sein, dass die danach auf der Seite vorgeschlagene Variante weniger allergisch auf Programmierfehler an anderer Stelle reagiert. Der hier gezeigte Code ist absolut korrekt, wenn die Annahmen über s zutreffen. Der andere Code danach ist auch korrekt (aber eingeschränkter im Funktionsumfang). Er ist zwar auch genauso inkorrekt, wenn die Annahmen über s nicht zutreffen, aber immerhin ist dann das schlimmste, was passieren kann, weniger schlimm oder unwahrscheinlicher als bei der von dir gezeigten Variante. Es ist durchaus vertretbar, etwas defensiver gegenüber Fehlern an anderen Stellen zu programmieren, wenn es wichtiger Code ist.

    Als Referenz, hier die auf der Seite vorgeschlagene "bessere" Lösung:

    char *buf;
    
    if ((buf = malloc(BUFSIZE)) != NULL) { // Überprüfung des Zeigers.
        strncpy(buf, s, BUFSIZE - 1);
        buf[BUFSIZE - 1] = '\0';  // Nachteil: Die Zeichenkette muss manuell terminiert werden.
    }
    return buf;
    


  • SeppJ schrieb:

    Die Argumentation hier soll wohl sein, dass die danach auf der Seite vorgeschlagene Variante weniger allergisch auf Programmierfehler an anderer Stelle reagiert.

    Danke, das beantwortet meine Frage.


Anmelden zum Antworten