Ich habe Google gefragt und etwas über StackOverflow recherchiert. Meine Frage ist, dass, wenn ich die Funktion main()
in einem C ++ - Programm eingeben und die allererste Variable deklariere, warum kann die Adresse dieser Variable bei verschiedenen Ausführungen variieren? Bitte beachten Sie mein Beispielprogramm unten:
Ergebnis bei Ausführung 1:
%Vor%Ergebnis bei Ausführung 2:
%Vor%Ergebnis bei Ausführung 3:
%Vor%Wie Sie sehen, bekomme ich unterschiedliche Ergebnisse bei verschiedenen Ausführungen. Die erste Zeile der Ausgabe entspricht der Adresse des zugewiesenen Speichers, die im Heap passieren sollte - wenn sie jedes Mal unterschiedliche Adressen zugewiesen bekommen, ergibt das für mich einen Sinn. Aber auch wenn ich die Adressen der lokalen Variablen - entsprechend der zweiten Zeile - drucke, sind die Ergebnisse immer noch unterschiedlich.
Auf den ersten Blick dachte ich, es liegt daran, dass das Programm eine physische Speicheradresse druckt, aber dieser Beitrag Virtueller Speicher oder Physischer Speicher widerlegt meinen anfänglichen Gedanken. Gibt es einen Grund dafür, dass die Ausführung der Programme "gleich" ist, ohne Threading, keine Benutzereingaben usw., dass es immer noch Speicherzuweisungen mit verschiedenen Adressen gibt?
Testumgebung:
Bei der Zuweisung auf dem Heap (mit dem Operator new
oder malloc()
und friends) muss Ihr Programm das Betriebssystem bitten, Ihren Heap-Speicher zuzuweisen. Viele Dinge hinter den Kulissen passieren im OS-Speichermanager (dessen Implementierungsdetails meistens über meiner Gehaltsstufe liegen: Speicherbereinigung, Konsolidierung von aufgearbeitetem Speicher, usw.) und es ist eine gute Sache nicht darüber nachdenken müssen.
Lokale Variablen werden auf dem Stack zugewiesen. Traditionell wäre die Stapelzuweisung wiederholbar, aber dies hat sich in den letzten Jahren geändert. Adressraum-Layout-Randomisierung (ASR) ist eine relativ neue Innovation in der OS-Speicherverwaltung, die Speicheradressen absichtlich in Stapelzuweisungen ( wie Sie sie beobachtet haben) zur Laufzeit nicht deterministisch. Es ist ein Sicherheitsmerkmal: Dies verhindert, dass schlechte Akteure Heap-Pufferüberläufe ausnutzen, denn wenn die ASLR-Implementierung entropisch genug ist, wer weiß, was am Ende des überlaufenden Puffers da sein wird?
Der Preis, den Sie für diese und andere Speicherverwaltungsfunktionen zahlen, ist die Kontrolle. Wetten auf die Adressen von Zuordnungen auf einer modernen (nicht eingebetteten) Plattform ist wie Powerball zu spielen: möglicherweise eine amüsante Ablenkung, aber kein praktikabler Plan für die Zukunft. Wenn Ihr Code auf einer AVR-ISA-Plattform oder einem solchen läuft, sind die Chancen vielleicht näher genug an Blackjack, so dass jemand verlockt werden könnte zu spielen, um zu gewinnen (sozusagen).
Wie auch immer, ich bin kein Glücksspieler, persönlich - wie ich oft sage, bevorzugen die Herren die Stapelzuteilung. Aber das ist im Grunde, warum Sie diese Ergebnisse bekommen.
Danke an @ T.C. für den Link und @SergeyA für den Vorschlag.
Tags und Links c memory c++ virtual-memory aslr