Ändert der Pufferüberlauf den Datentyp der Variablen, die überschrieben wird? [geschlossen]

8

Angenommen, ich habe ein C-Zeichen-Array char buf[15]. Angenommen, die Variablen int set_me = 0der Variablen werden direkt danach an einem Speicherort gespeichert char buf[15]. Wenn ich bufmit einer Zeichenfolge überlaufen "aaabbbcccdddeee\xef\xbe\xad\xde"würde, würde sich set_meder Datentyp von einer Ganzzahl in ein Zeichenarray ändern?

Darien Springer
quelle
3
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.

Antworten:

33

Nein.

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

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


Variablen sind in der Hardware nicht vorhanden. In der Hardware haben Sie Speicherorte und die Anweisungen, die auf ihnen arbeiten.

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

Beispielsweise könnte das Byte 0x41 als UTF-8-codiertes Zeichen interpretiert werden A. Es könnte auch als Einzelbyte-Ganzzahl interpretiert werden 65. Es könnte auch als ein Byte in einer Mehrbyte-Ganzzahl oder Gleitkommazahl oder als ein Byte in einer Mehrbyte-Zeichencodierung interpretiert werden. Es könnte das Bitset sein 0b1000001. Alle aus demselben 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, die Ihr Compiler oder Ihre Sprache erwarten könnten. In Bezug auf die Hardware 1 schreiben Sie jedoch Bytes (einzeln oder mehrfach) in 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.

Wenn Sie das nächste Mal in Ihrem Code auf diesen Speicherort zugreifen, werden die Anweisungen wie ursprünglich definiert ausgeführt. Wenn sie dort beispielsweise eine Nummer erwartet haben, werden sie auf alle Datenbytes so reagieren, als wären sie eine Nummer.


Angenommen, es inthandelt sich um eine 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 intSpeicherort des 'jetzt 0xEFBEADDEunter der Annahme eines Big-Endian-Systems 2 enthält . Dies ist das vorzeichenbehaftete 32-Bit-Int -272716322. Wenn Sie nun denselben Speicher wie ein vorzeichenloses int ( uint) interpretieren , ist dies 4022250974stattdessen der Fall . Für genau dieselben Daten im Speicher hängt die Bedeutung ganz davon ab, wie Sie sie anzeigen.


1 Es gibt einige Mechanismen, die Sie daran hindern, in geschützte Speicherbereiche zu schreiben, und die Ihr Programm zum Absturz bringen, wenn Sie dies versuchen.

2 x86 ist eigentlich Little-Endian, was bedeutet, dass Sie die Bytes, aus denen sich ein größerer Wert zusammensetzt, rückwärts interpretieren. Auf x86 müssten Sie stattdessen 0xDEADBEEFsigniert -559038737oder nicht signiert angeben 3735928559.

Bob
quelle
Also 0xdeadbeef, auf einer x86 - Architektur, würde weniger Platz im Speicher als sein Dezimal - Pendant 3735928559?
Darien Springer
2
@DarienSpringer Beide belegen 4 Byte Speicher - sie sind dieselbe 4-Byte-Sequenz. Sie sind im Speicher identisch. Wenn Sie möchten, können Sie alles als Basis 2 (binär) im Speicher betrachten. Wenn Sie sie dann anzeigen (zur Ausgabe in eine Zeichenfolge konvertieren), können Sie eine Basis für die Anzeige auswählen - das Hex ist die Basis 16 und die Dezimalstelle die Basis 10. Die Zeichenfolgendarstellungen werden an einem anderen Speicherort gespeichert und können unterschiedliche Beträge verwenden Speicher (da jedes Zeichen ein separates Byte ist). Die Zeichenfolge 0xDEADBEEF wird im Speicher als gespeichert 0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46.
Bob
5
@DarienSpringer Anders ausgedrückt, eine Zahl ist dieselbe Zahl, egal in welcher Basis sie sich befindet. Hex ist eine bequeme (kompakte) Möglichkeit, Binärdateien anzuzeigen. Physisch ist es binär. Menschen mögen Dezimalstellen, daher zeigen wir Zahlen häufiger als Dezimalzahlen an. Bis wir jedoch zum Anzeigeschritt gelangen, arbeiten alle numerischen Operationen (Addieren, Subtrahieren, Multiplizieren usw.) mit denselben Binärdaten im Speicher.
Bob
1
"Sie können sehen, dass der Speicherort des Int jetzt 0xEFBEADDE ist." Nitpick: Ich weiß, dass Sie dies nicht beabsichtigt haben, aber es hört sich so an, als würden Sie sagen, dass sich der Int am Speicherort befindet 0xEFBEADDE. Vielleicht das ein bisschen umformulieren. Ansonsten ist dies eine hervorragende Antwort - ich mag besonders die "Ansicht" -Analogie und die "Schielen" -Idee :)
Leichtigkeitsrennen im Orbit
@ LightnessRacesinOrbit Guter Punkt. Bearbeitet.
Bob
2

Aus C-Sicht 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 über undefiniertes Verhalten verfügt. Dies ist die wörtliche Bedeutung von undefiniertem Verhalten im C-Standard. Und Pufferüberläufe sind eine Form davon.

Ich schrieb anfangs "die C-Regeln gelten nicht mehr", aber tatsächlich ist das undefinierte Verhalten rückwirkend. C-Regeln gelten nicht für Programme, die in Zukunft ein undefiniertes Verhalten aufweisen werden.

MSalters
quelle