Frage

Sehen Sie das Programm unter

    char str[5];
    strcpy(str,"Hello12345678");
    printf("%s",str);

Wenn Sie dieses Programm ausführen, gibt Segmentierungsfehler.

Aber wenn strcpy mit folgenden ersetzt wird, Programm läuft gut.

strcpy(str,"Hello1234567");

So Frage ist es sollte abstürzen, wenn eine andere Zeichenfolge von mehr als 5 Zeichen Länge auf str zu kopieren versuchen.

Also, warum es nicht für „Hello1234567“ abstürzt und nur für „Hello12345678“, dh den String mit einer Länge von 13 oder mehr als 13 abstürzt.

Dieses Programm wurde auf 32-Bit-Computern ausgeführt werden.

War es hilfreich?

Lösung

Es gibt drei Arten von Standards Verhalten sollten Sie interessieren.

1 / Definierte Verhalten . Dies wird auf all Einhaltung Implementierungen arbeiten. Verwenden Sie diese frei.

2 / Implementierung definiert Verhalten . Wie bereits erwähnt, hängt es von der Implementierung, aber zumindest ist es nach wie vor definiert. Implementationen sind erforderlich, um zu dokumentieren, was sie in diesen Fällen zu tun. Verwenden Sie diese Option, wenn Sie kümmern sich nicht um die Portabilität.

3 / Undefined Verhalten . Alles kann passieren. Und wir meinen alles , bis einschließlich den gesamten Computer in eine nackte Singularität kollabiert und Schlucken sich, Sie und einen großen Teil Ihrer Kollegen. Nie verwenden. Je! Ernsthaft! Lassen Sie mich nicht dort drüben kommen.

Kopieren von mehr als 4 Zeichen und ein Null-Byte zu einem char[5] ist nicht definiertes Verhalten.

Im Ernst, spielt es keine Rolle, warum Ihr Programm mit 14 Zeichen stürzt aber nicht mehr als 13, sind Sie mit ziemlicher Sicherheit überschreiben einige Nicht-Absturz Informationen auf dem Stapel und Ihr Programm wird höchstwahrscheinlich zu falschen Ergebnissen führen sowieso. In der Tat ist der Absturz besser, da es zumindest hält Sie auf den möglicherweise schlechten Auswirkungen zu verlassen.

Erhöhen Sie die Größe des Arrays, um etwas mehr geeignet (char[14] in diesem Fall mit den verfügbaren Informationen) oder eine andere Datenstruktur verwenden, das fertig wird.


Update:

Da Sie so besorgt scheinen, herauszufinden, warum eine zusätzliche 7 Zeichen keine Probleme verursacht, aber 8 Zeichen ist, lassen Sie uns die mögliche Stapel Layout vorstellen main() beim Betreten. Ich sage „möglich“, da das tatsächliche Layout ist abhängig von der Aufrufkonvention, die Ihr Compiler verwendet. Da der C Start-up-Code main() mit argc und argv nennt, für einen main() der Stapel zu Beginn der char[5], nach Raum Zuteilung könnte wie folgt aussehen:

+------------------------------------+
| C start-up code return address (4) |
| argc (4)                           |
| argv (4)                           |
| x = char[5] (5)                    |
+------------------------------------+

Wenn Sie schreiben die Bytes Hello1234567\0 mit:

strcpy (x, "Hello1234567");

x, es überschreibt die argc und argv aber bei der Rückkehr von main(), das ist okay. Insbesondere Hello x auffüllt, auffüllt 1234 argv und 567\0 auffüllt argc. Vorausgesetzt, Sie sind nicht wirklich versuchen verwenden argc und / oder argv danach, Sie in Ordnung sein:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |
| argc (4)                           |   '567<NUL>'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

Wenn Sie jedoch Hello12345678\0 schreiben (beachten Sie die extra „8“) x, überschreibt er die argc und argv und auch ein Byte der Absenderadresse, so dass, wenn main() zurückzukehren versucht, der C Start-up-Code, es weg in Feenland geht statt:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |   '<NUL>'
| argc (4)                           |   '5678'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

Auch dies hängt ganz von der Aufrufkonvention des Compilers. Es ist möglich, einen anderen Compiler würde immer polstern Arrays auf ein Vielfaches von 4 Bytes und der Code würde nicht fehlschlagen, bis Sie drei weitere Zeichen geschrieben. Selbst die gleichen Compiler Variablen auf dem Stack-Frame unterschiedlich zuweisen können, um sicherzustellen, Ausrichtung erfüllt ist.

Das ist, was sie nicht definiert bedeuten: Sie müssen nicht wissen was wird passieren

.

Andere Tipps

Sie Kopieren auf den Stapel, es ist so abhängig, was der Compiler auf den Stapel gelegt hat, für wie viel zusätzliche Daten benötigt werden, um Ihr Programm zum Absturz bringen.

Einige Compiler könnte Code erzeugen, der mit nur einem einzigen Byte über die Puffergröße abstürzen wird - es ist nicht definiert, was das Verhalten

.

Ich denke, 13er genug ist, um die Rücksprungadresse, oder etwas ähnliches, die, wenn sie Ihre Funktion zurück stürzt zu überschreiben. Aber ein anderer Compiler oder eine andere Plattform könnte / wird mit einer anderen Länge zum Absturz bringen.

Auch Ihr Programm könnte mit einer anderen Länge abstürze, wenn sie für eine längere Zeit laufen, wenn etwas weniger wichtig überschrieben wurde.

Für 32-Bit-Intel-Plattform ist die Erklärung die folgende. Wenn Sie char [5] erklären stapeln der Compiler wirklich 8 Bytes wegen der Ausrichtung zuweist. Dann typischen es ist für Funktionen im folgenden Prolog haben:

push ebp
mov ebp, esp

Das spart EBP Registrierungswert auf dem Stapel, dann bewegt sich esp Wert in EBP Register für esp Wert über die Parameter zuzugreifen. Dies führt zu 4 weiteren Bytes auf Stapel mit EBP Wert belegt werden.

Im Epilog EBP wird gestellt, aber ihr Wert wird in der Regel nur für den Zugriff auf Stapel zugewiesenen Funktionsparameter verwendet, so überschreibt es nicht in den meisten Fällen verletzen kann.

So können Sie das folgende Layout haben (Stack wächst nach unten auf Intel.): 8 Bytes für Ihren Array, dann 4 Bytes für EBP, dann in der Regel der Absenderadresse

Dies ist, warum Sie mindestens 13 Bytes überschrieben werden müssen Ihr Programm zum Absturz bringen.

zu den oben genannten Antworten hinzuzufügen: Sie Fehler wie diese mit einem Werkzeug testen können wie Valgrind . Wenn Sie unter Windows sind, haben einen Blick auf diesen Thread SO .

Es hängt davon ab, was nach dem „str“ Array auf dem Stapel ist. Sie passieren einfach nicht auf irgendetwas zu trampeln kritisch, bis Sie, dass viele Zeichen kopiert werden.

Also, es wird auf abhängen, was sonst noch in der Funktion ist, der Compiler Sie verwenden und möglicherweise die Compiler-Optionen zu.

13 ist 5 + 8, was darauf hindeutet, gibt es zwei nicht-kritische Worte nach dem str Array, dann etwas kritisch (vielleicht die Absenderadresse)

Das ist die reine Schönheit des undefinierten Verhaltens (UB): es ist nicht definiert

.

Ihr Code:

char str[5];
strcpy(str,"Hello12345678");

Schreibt 14 Byte / Zeichen str die nur 5 Byte / Zeichen halten kann. Dies ruft UB.

. F: Warum ist es nicht für „Hello1234567“ abstürzt und nur für „Hello12345678“, dh den String mit einer Länge von 13 oder mehr als 13 abstürzt

  

Da das Verhalten ist nicht definiert.   Verwenden Sie Strncpy. Sehen Sie diese Seite    http://en.wikipedia.org/wiki/Strcpy   für weitere Informationen.

Strncpy ist unsicher, da es keine NULL Kündigung nicht hinzufügen, wenn die Quellzeichenfolge eine Länge> = n, wobei n die Größe des Zielstrings.

char s[5];
strncpy(s,5,"test12345");
printf("%s",s); // crash

Wir verwenden immer strlcpy diese zu lindern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top