C++ Speicherzugriffsfehler - Wie entstehen sie ?

Tockra

Lt. Commander
Registriert
Dez. 2008
Beiträge
1.063
Hallo Leute!

Ich würde gerne wissen, wann Speicherzugriffsfehler entstehen (ich auf einen Bereich zugreife und das OS das nicht gestattet).
Könnte z.B. in dieser Situation ein Speicherzugriffsfehler entstehen?:

Code:
vector<int> foo;
foo.push_back(42);
int *bar = &foo.at(0);
while(true) {
	foo.push_back(i);
	cout << *bar<< endl; // mir ist bewusst, dass hier nicht immer 42 steht 
}

Wie "erzwinge" ich Speicherzugriffsfehler ? Welche Adresse müsste ich dafür dereferenzieren ?

Gruß
T
 
Code:
int* array = new int[20];
std::cout << array[20] << std::endl

Sollte einen Speicherzugriffsfehler geben, da Index 20 nicht reserviert wurde, nur 0-19 sind ansprechbar.

Allgemein entstehen die einfach da wo ein Pointer auf eine Adresse mit Speicherbereich zeigt, die dein Programm nicht reserviert hat.
 
Zuletzt bearbeitet:
Was auf jeden fall einen Fehler verursacht

Code:
typedef struct dummy 
{ 
int a;
int b;
} TestCase;

    TestCase *x=NULL;
    x->b =18;
Normalerweise erkennt das System einen nullpointer, aber hier wird auf den Eintrag b zugegriffen
das währe dann eigentlich die Speicheradresse 4
und das ist OS eigener Speicher (oder sonstwie reserviert)
 
Ich dachte meine Programme nutzen einen logischen Adressbereich und alle nicht reservierten Adressen, haben nur keine Zuordnung zu einer realen Adresse im Speicher!?
Wenn die CPU keine reale RAM-Seite zu einer virtuellen Addresse findet, schmeißt sie eine Exception, das Betriebssystem fängt sie ab und schießt dann dein Programm mit dem SIGSEGV-Signal oder entsprechendem Windows-Äquivalent ab.

Das Beispielprogramm von DaysShadow wird höchstwahrscheinlich nicht abstürzen, denn obwohl der Index 20 nicht mehr zum Array gehört, wird der wahrscheinlich noch im reservierten Bereich des Programms liegt. In dem Fall entsteht undefiniertes Verhalten.
 
Tockra schrieb:
PS: Unter Ubuntu gibt die der von dir geschriebene Programmcode keinen Fehler!

Muss er auch nicht. Da der falsche Zugriff erstmal nur undefined behaviour ist.
Das kann zu einer Zugriffsverletzung führen, muss aber nicht.
 
Im debug modus kannst du normalerweise einfach
Code:
int *a = nullptr;
std::cout << *a<< std::endl;
schreiben. Im release modus kanns aber passieren, dass dir der Compiler das wegoptimiert.
Um genau zu sein gibt es in standard c++ keine Möglichkeit einen garantierten Speicherzugriffsfehler zu produzieren, weil das dereferenzieren eines ungültigen Speicherbereichs per Definition undefiniertes Verhalten bedeutet und damit alles passieren kann.
 
Zuletzt bearbeitet:
Tockra schrieb:
Ich dachte meine Programme nutzen einen logischen Adressbereich und alle nicht reservierten Adressen, haben nur keine Zuordnung zu einer realen Adresse im Speicher!?
PS: Unter Ubuntu gibt die der von dir geschriebene Programmcode keinen Fehler!
Nein das stimmt so nicht ganz
virtuelle Speicherbereiche werden reellen speicher zugeordnet (sogenanntes paging)
Solange du innerhalb so einer Page bleibst erkennt das System keine speicherverletzung weil es dazu jeden zugriff einzel checken müsste und es um äonen zu langsam wäre..
Mit solch einen Fehler kannst du nämlich nur dein eigenes Programm zerschießen, aber nicht ein OS in Gefahr bringen ...

Vorschlag das ausgaben einfach in einer schleife machen und einfach nach oben zählen
irgendwann sagt das System... ähhh.. du bist böse , stop!
 
Wenn ichs recht im Kopf hab weisen Linux und Windows den Prozessen im Normalfall 4Kb große Pages zu.
 
Zuletzt bearbeitet:
Tockra schrieb:
was ist der sog. reservierte Bereich des Programms?:
Je nach OS werden verschiedene Teile des Speicherbereichs für spezielle Zwecke reserviert.
Da liegen dann sachen wie System und Processvariablen
z.B. in war in alten DOS Zeiten der Bereich über 640 kb reseviert, teilweise für die Grafikkarte, usw...

für dich als Entwickler ist das eigentlich komplett schnuppe weil sich da der Compiler/Linker und auch das OS darum kümmern
Vermutlich nichtmal als Treiber Entwickler musst du dich darum kümmern.
 
Alles klar, das dachte ich mir. Sobald ich also eine Page verlasse und in die nächste Page laufe, zu der mein OS keinen Eintrag in der Kacheltabelle hat, meckert das System.

Aber um das klar zu stellen, ein Speicherzugriffsfehler kann bei keinem Betriebssystem durch den von mir ganz oben geschriebenen Code entstehen, oder kann es passieren, dass irgendwann die Page von bar nicht mehr existiert und somit ein Zugriff auf einem nicht zugewiesenen Bereich entsteht?

Also interessant ist für mich die Frage, ob der alte Bereich eines vectors, nach verschieben des Inhaltes in einem neuen (größeren) Bereich noch sicher dereferenziert werden kann!?
 
Zuletzt bearbeitet:
Kann schon - wenn das Freigeben des Speichers dazu führt, dass die Page wieder ans OS zurückgegeben wird.
 
@Tockra: K.A. ich kenn mich mit den Details der Speicherverwaltung nicht aus.

Mal anders gefragt: Was willst du erreichen? Speicherzugriffsfehler sind - in der Theorie - nicht das schlimmste, was dir passieren kann.
 
Das ist sicherlich schon an irgend einer Stelle erwähnt worden, aber an erster Stelle erzeugst du mit solchem Vorgehen erst mal keine Speicherschutzverletzung sondern schlicht und ergreifend undefiniertes Verhalten. Ob daraus letzten Endes eine Speicherschutzverletzung, ein scheinbar fehlerfrei funktionierender aber doch auf subtile Weise fehlerhafter Programmdurchlauf oder ein explodierender Computer resultiert, hängt vom OS und dem Compiler ab.
 

Ähnliche Themen

D
Antworten
2
Aufrufe
1.362
D
Zurück
Oben