Ändert der Pufferüberlauf den Datentyp der zu überschreibenden Variablen?

1839
Darien Springer

Angenommen, ich habe ein C-Zeichen-Array char buf[15]. Angenommen, die Variable int set_me = 0hat ihre Daten direkt hinter einem Speicherplatz gespeichert char buf[15]. Wenn ich bufmit string überläuft "aaabbbcccdddeee\xef\xbe\xad\xde", würde sich set_meder Datentyp von einer Ganzzahl in ein Zeichenarray ändern?

8
Kommt darauf an, wer die Daten interpretiert. endlich ist alles binär. So wie Sie es interpretieren, kann es ein gültiger ganzzahliger Wert sein oder einen Umwandlungsfehler verursachen Ganesh R. vor 5 Jahren 3

2 Antworten auf die Frage

33
Bob

Nein.

Der "Datentyp" einer Variablen ist nur im Quellcode relevant (und sogar dann nur in einigen Sprachen). Sie teilt dem Compiler mit, wie die Variable behandelt werden soll.

Diese übergeordneten Datentypen sind in kompiliertem (nativem) Code nicht als solche vorhanden. Sie können sich darauf auswirken, welche Anweisungen ein Compiler generiert, aber es ist den Anweisungen selbst egal, ob die Daten ein Zeichen oder eine Zahl darstellen.


Variablen sind in der Hardware nicht vorhanden. In der Hardware verfügen Sie über Speicherorte und die dazugehörigen Anweisungen.

Eine Variable kann als eine Ansicht der Daten an einem Speicherort betrachtet werden. Wenn Sie denselben Speicher etwas anders betrachten (eine andere Variable mit einem anderen Typ, die sich auf denselben Speicherort bezieht), kann derselbe Binärwert eine andere Bedeutung haben .

Das Byte 0x41 könnte beispielsweise als UTF-8-codiertes Zeichen interpretiert werden A. Es könnte auch als Einzelbyte-Integer interpretiert werden 65. Es könnte auch als ein Byte in einer Multi-Byte-Integer- oder Gleitkommazahl oder als ein Byte in einer Multi-Byte-Zeichencodierung interpretiert werden. Es könnte das Bitset sein 0b1000001. Alle vom selben Byte am selben Speicherort. In der C - Sprache, können Sie diesen Effekt sehen durch Gießen auf diese verschiedenen Arten.

Wenn Sie einen "Pufferüberlauf" haben, tun Sie etwas außerhalb der Grenzen dessen, was Ihr Compiler oder Ihre Sprache erwarten kann. In Bezug auf die Hardware 1 schreiben Sie jedoch Bytes (einzeln oder mehrere) an einen Speicherort. Ein Speicherort hat keinen "Typ". Tatsächlich weiß die Hardware nicht einmal, dass ein bestimmter Satz von Bytes ein Array oder einen Puffer in Ihrem Code bildet.

Wo immer Sie als Nächstes auf diesen Speicherplatz in Ihrem Code zugreifen, werden die Anweisungen wie ursprünglich definiert ausgeführt. Wenn sie beispielsweise eine Zahl dort erwartet haben, werden sie mit den Datenbytes wie mit einer Zahl umgehen.


Angenommen, Sie verwenden inteine vorzeichenbehaftete 4-Byte-Ganzzahl (32-Bit):

+-------------+--------------------------------------------+-----------+ | Source code | char[15] | int | +-------------+--------------------------------------------------------+ | Memory |61|61|61|62|62|62|63|63|63|64|64|64|65|65|65|EF|BE|AD|DE| +-------------+--------------------------------------------------------+ 

Sie können sehen, dass der intSpeicherplatz jetzt vorhanden ist 0xEFBEADDE, vorausgesetzt, ein Big-Endian-System 2 . Dies ist das vorzeichenbehaftete 32-Bit-Int -272716322. Wenn Sie nun dieselbe Erinnerung als int ( uint) ohne Vorzeichen interpretieren, würde dies 4022250974stattdessen der Fall sein . Für genau dieselben Daten im Speicher hängt die Bedeutung vollständig davon ab, wie Sie sie anzeigen.


1 Es gibt einige Mechanismen, die das Schreiben in geschützte Speicherbereiche verhindern und Ihr Programm zum Absturz bringen, wenn Sie dies versuchen.

2 x86 ist eigentlich Little-Endian, dh Sie interpretieren die Bytes, die einen höheren Wert bilden, rückwärts. Auf x86 müsstest du stattdessen 0xDEADBEEFsigniert -559038737oder unsigniert geben 3735928559.

Auf einer x86-Architektur würde also "0xdeadbeef" weniger Speicherplatz beanspruchen als sein dezimales Pendant "3735928559"? Darien Springer vor 5 Jahren 0
@DarienSpringer Beide haben das gleiche Bitmuster. dsstorefile1 vor 5 Jahren 1
@DarienSpringer Beide belegen 4 Byte Speicherplatz - es handelt sich um dieselbe 4-Byte-Sequenz. Sie sind im Gedächtnis identisch. Wenn Sie möchten, können Sie dies als Basis 2 (binär) im Speicher betrachten. Wenn Sie sie anzeigen (in eine Zeichenfolge für die Ausgabe konvertieren), können Sie eine Basis für die Anzeige auswählen. Das Hex ist die Basis 16 und die Dezimalzahl ist die Basis 10. Die Darstellung der Zeichenfolgen wird an einem anderen Speicherort gespeichert und kann unterschiedliche Beträge verwenden des Speichers (da jedes Zeichen ein separates Byte ist). Die * Zeichenfolge * `0xDEADBEEF` wird im Speicher als` 0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46` gespeichert. Bob vor 5 Jahren 2
@DarienSpringer Mit anderen Worten, eine Zahl ist die gleiche Zahl, egal in welcher Basis sie sich befindet. Hex ist eine bequeme (kompakte) Art, Binärdarstellungen anzuzeigen. Physisch ist es binär. Menschen mögen Dezimalzahlen, daher werden Zahlen häufiger als Dezimalzahlen angezeigt. Bis zum Anzeigeschritt arbeiten jedoch alle numerischen Operationen (Addieren, Subtrahieren, Multiplizieren usw.) mit den gleichen binären Daten im Speicher. Bob vor 5 Jahren 5
_ "Sie können sehen, dass der Speicherort des Inters jetzt 0xEFBEADDE ist" _ Nitpick: Ich weiß, dass Sie das nicht beabsichtigt haben, aber es klingt, als würden Sie sagen, das Int sei _at_ der Speicherort `0xEFBEADDE '. Vielleicht formulieren Sie das ein bisschen. Ansonsten ist das eine großartige Antwort - ich mag besonders die "View" -Analogie und die "Schielen" -Idee :) Lightness Races in Orbit vor 5 Jahren 1
@LightnessRacesinOrbit Guter Punkt. Bearbeitet Bob vor 5 Jahren 0
2
MSalters

Aus einer C-Perspektive wäre die Antwort "Wer weiß? Es ist undefiniertes Verhalten".

Typen sind ein C-Konzept, keine Hardware. Die C-Regeln gelten jedoch nicht, wenn Ihr Programm Undefined Behavior hat. Dies ist die wörtliche Bedeutung von Undefined Behavior im C-Standard. Und Pufferüberläufe sind eine Form davon.

Ich schrieb anfangs "die C-Regeln gelten nicht mehr", aber das Undefinierte Verhalten ist tatsächlich rückwirkend. C-Regeln gelten nicht für ein Programm, das zukünftig undefiniertes Verhalten hat.