2009-11-17 10 views
5

Ich bekomme ein seltsames Ergebnis in den folgenden C-Code.malloc() und Heap-Speicher

int main() 
{ 
    int *p = (int *) malloc(100); 
    p[120] = 5; 
    printf("\n %d", p[120]); 
} 

Da ich nur 100 Bytes zugewiesen habe, sollte dieser Code einen Segmentierungsfehler verursachen. Es gibt jedoch '5' aus und gibt keinen Laufzeitfehler. Kann mir bitte jemand den Grund erklären?

+4

Wahrscheinlich nur Glück gehabt. –

+5

Du hast eine 5 an einen Ort geschrieben, der dir nicht gehört hat. Wenn der Besitzer dieses Ortes nicht mochte, was Sie zu seinem Haus getan haben, wird es seine Rache bekommen. ** Vorsicht **, es könnte zu Ihrem USB-Festplattentreiber gehören und formatiert das nächste Laufwerk, das Sie einlegen. – pmg

+4

@pmg: Realistisch gesehen ist das bei einem modernen Protected-Mode-Betriebssystem nicht sehr wahrscheinlich. – bcat

Antwort

20

Nein, der Code sollte nicht (unbedingt) einen segfault ergeben. Ein Segmentfehler tritt auf, wenn Sie versuchen, auf eine virtuelle Speicherseite zuzugreifen, die Ihrem Prozess nicht zugeordnet ist.

Der "Heap" oder "Free Store" ist eine Region von virtuellen Speicherseiten, die Ihrem Prozess gehören. Die malloc()-API unterteilt diese Region in Blöcke und gibt einen Zeiger auf den Block zurück.

Wenn Sie nach dem Ende des Blocks adressieren, auf den Sie einen Zeiger haben, greifen Sie normalerweise auf den Speicher zu, der Teil des Heapspeichers ist, aber nicht Teil Ihres zugewiesenen Blocks. Auf diese Weise können Sie andere Heap-Blöcke oder sogar die Datenstrukturen korrumpieren, die malloc() verwendet, um den Heap zu definieren.

Weitere Informationen über Heapbeschädigung und Methoden in der Debug-Version des Codes zu erkennen, das ist ein großes Buch:

Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire alt text http://ecx.images-amazon.com/images/I/5148TK6JCVL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg

Ein Nachtrag zum pedantisch: In seltenen Fällen Durch Zugriff auf Speicher über das Ende eines Heap-Blocks hinaus können Sie auf Speicher zugreifen, der nicht Teil des Heapspeichers ist. In diesen Fällen erhalten Sie möglicherweise den von Ihnen erwarteten Segmentierungsfehler. Sie könnten auch eine andere Datenstruktur als den Heap beschädigen. Es ist wirklich eine Frage des Zufalls. Der Heap selbst ist jedoch im Vergleich zu typischen Heap-Blöcken sehr groß, so dass 99% des Timecodes wie Ihr Beispiel den Heap verfälschen. Das Beispiel, das Sie angeben, fällt in diesen 99% -Fall.

+0

Eigentlich, da er gebeten hat, 20 Bytes nach dem Ende des Stapels zu ändern, könnte er, abhängig von der Architektur und dem umgebenden Code, stattdessen den Stapel schleusen oder sogar das Programm selbst ändern. Das Verhalten ist wirklich undefiniert. –

+2

T.E.D. Das ist nur "irgendwie" wahr. Er verwendet zweifellos eine Maschine mit einer virtuellen Speicherseitengröße. Vermutlich hat ausführbarer Code einen anderen VM-Schutz als Heap. Ich würde wetten, er ist auf einem solchen System, weil die C-Standardbibliothek malloc() Funktion existiert. Was Sie schreiben, trifft jedoch insbesondere auf das Radio Shack Model III zu, auf dem TRS-DOS auf einem Z-80 läuft. ;) –

+0

Und ja, sogar auf einem VM-Pagesystem könnte was du schreibst passieren. Es ist einfach nicht so wahrscheinlich und es ist nicht sehr pädagogisch, in das Detail zu gehen, das selten von Bedeutung ist. Beheben Sie das Problem auf der Ebene, auf der es angegeben ist. Vermeiden Sie Pedanterie. –

0

Sie schreiben in den Speicher, den Sie nicht zugeordnet haben. Das Programm könnte möglicherweise aufgrund der Auswirkungen der Heap-Beschädigung beendet werden, wenn die Laufzeit ausreichend lang ist.

6

Ungültige Speicherzugriffe verursachen nicht immer einen Segmentierungsfehler, einen Busfehler oder einen anderen Absturz. Wenn beispielsweise unmittelbar nach dem Array ein weiterer Block zugewiesen wird, ändern Sie die Werte in , die Block - was alles sein könnte.

0

Sie schreiben in nicht initialisierten Speicher; das ist in C erlaubt, es ist einfach keine gute Idee. So etwas sollte nicht unbedingt einen Segmentierungsfehler verursachen.

+2

Ihre Verwendung des Wortes "erlaubt" ist irreführend. Es ist syntaktisch gültig, ruft aber undefiniertes Verhalten auf. –

3

Nein, es kann einen segfault geben, aber nur wenn der Speicher außerhalb Ihres Prozesses ist. Andernfalls wird nur ein anderer Bereich des Programmspeichers geändert. C überprüft dies nicht und schützt Sie auch nicht in den oben genannten Fällen. Viele Software-Cracker verwenden dieses "Feature" von C, um ein Programm mit erhöhten Rechten neu zu schreiben und sich selbst die Kontrolle über Ihre Maschine zu geben. Es heißt buffer overflow exploit.

Aus diesem Grund sollte C (und C++) für neue Software lieber für sicherere Sprachen wie Ada vermieden werden.

+1

Ich weiß, dass der letzte Satz mich negativ stimmen wird. Es ist mir egal. Das ist wahr. –

+0

+1 von mir. Ich stimme vollkommen zu. – lesscode

0

Häufige Ursachen für Segmentierungsfehler:

  • dereferencing Zeiger mit ungültigem Wert
  • dereferencing Nullzeiger
  • versucht, in eine schreiben Nur-Lese-Segment
  • Frei ing falscher Zeiger oder un Blöcke.

    int * x = 0;

    x = 200;/ Ursachen Segmentation fault */

Segfaults von MMU Ausnahmen generiert werden, basieren auf, was ist fest entschlossen, ein illegaler Speicherzugriff zu sein. Abhängig davon, wie das Betriebssystem seinen Speicher strukturiert, kann ein Speicherzugriff auf einem Betriebssystem legal sein (obwohl falsch) und auf einem anderen Betriebssystem ist es möglicherweise illegal.

+0

Dies ist Jahre zu spät, aber ... x = 200 ist in Ordnung, * x = 200 führt zu segfault. –