7 Stimmen

Warum wird mehr Speicher einer lokalen Variablen im Stapel zugewiesen als in C++ erforderlich ist?

Ich habe über Buffer Overflow gelesen. Ich habe etwas Seltsames über die Speicherzuweisung von lokalen Variablen im Stack gefunden.

int f1 ()
{
    char string1[12];
    char string2[4];
}

Hier erfolgt die Zuweisung im Stack.

Jetzt, in GCC werden 4 Bytes für string2 zugewiesen, aber wenn ich eine andere Größe als eine Zweierpotenz (bis zu 16) deklariere, werden vom Compiler 16 Bytes zugewiesen. Das heißt, wenn ich string2 in 3, 5, 6, 7,..., 15 Bytes allokiere, dann werden durch den Compiler 16 Bytes zugewiesen, aber wenn ich eine Zweierpotenz wie 1, 2, 4, 8,... zuweise, dann wird genau dieselbe Größe zugewiesen. Wenn ich mehr als 16 Bytes (nicht als Zweierpotenz) zuweise, dann werden 32 Bytes zugewiesen (ich vermute bis zu 32 Bytes).

Währenddessen, in Visual Studio, werden 9 Bytes allokiert, wenn ich 1 Byte zuweise, 12 Bytes werden allokiert, wenn ich 2-4 Bytes zuweise, und 16 Bytes werden allokiert, wenn ich 5-8 Bytes zuweise, vom Compiler.

Kennt jemand den Grund für diese Art der Zuweisung???

Zumindest in Visual Studio erhalte ich bei einem Buffer Overflow einen Debug-Fehler, aber in GCC passiert nichts. GCC gibt nur eine Segmentation Fault aus, wenn ein zu großer Overflow auftritt.

14voto

Hans Passant Punkte 894572

Stackframe-Größen werden durch Speicherausrichtungswahl beeinflusst, normalerweise ein Vielfaches von 4 für 32-Bit-Code und ein Vielfaches von 8 für 64-Bit-Code.

Beide Compiler können die Überprüfung der Stackframe-Korruption mit einem Wachhund einschließen, einem zusätzlichen 32-Bit-Wert oben auf dem Stack, der bei Funktionseintritt initialisiert und bei Funktionsende überprüft wird. Wenn sich der Wachhundwert geändert hat, tritt ein Programmabbruch auf, da der Stackframe wahrscheinlich durch bösartigen Code beschädigt wurde, der die Funktionsrückgabeadresse verändern und dazu bringen kann, an eine beliebige Stelle zurückzukehren. Ein sehr beliebter Malware-Injektionsvektor.

MSVC hat die Option /RTC, die standardmäßig in der Debug-Konfiguration aktiviert ist. Dadurch werden diese Wächter zwischen jeder lokalen Variablen hinzugefügt. So können Buffer Overflow-Probleme bei jeder einzelnen Variablen erkannt werden.

Diese Wächter nehmen natürlich zusätzlichen Platz ein, was sich auf die Größe des Stackframes auswirkt.

6voto

Manu343726 Punkte 13666

Dies liegt an der Speicherausrichtung. Für die CPU ist es einfacher auf Speicheradressen zuzugreifen, die Vielfache der angeforderten Datengröße sind.
Deshalb füllt der Compiler Ihre Struktur mit leeren Bytes auf, um die Struktur auszurichten. Zum Beispiel:

struct foo
{
    char a;
    int b, c;
    short d;
    bool e;
    double f;
};

Im Idealfall beträgt die Größe dieser Struktur (vorausgesetzt die Größe von bool ist 1 Byte, char 1 Byte, int 4 Byte, short 2 Byte, double 8 Byte) 20 Bytes. Doch in der Praxis fügt der Compiler "Löcher" in die Struktur ein, um den Speicher auszurichten:

         0 | 1 | 2 | 3
-----------+---+---+---
0x0000 | a |   |   |
-----------+---+---+---
0x0004 | b | b | b | b
-----------+---+---+---
0x0008 | c | c | c | c
-----------+---+---+---
0x000C | d | d |   |
-----------+---+---+---
0x0010 | e |   |   |
-----------+---+---+---
0x0014 | f | f | f | f
-----------+---+---+---
0x0018 | f | f | f | f
-------+---+---+---+---

0voto

lcestari Punkte 178

Ich erinnere mich, dass der Grund dafür die Optimierung und vielleicht auch die Größe ist. Ein weiteres Beispiel dafür ist der boolsche Typ, der normalerweise 8 Bits verbraucht, aber auch nur einer sein könnte. Dies kann sich je nach den verschiedenen Compilern stark unterscheiden. Weitere Informationen zum boolschen Typ findest du unter Warum haben char und bool die gleiche Größe in c++?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X