Verwendung von nicht zugeordnetem Speicher ohne Fehler?

8

Warum funktioniert das?

%Vor%

während dieser nicht?

%Vor%

Ich habe beide Programme auf Win XP mit MS VS 2008 ausprobiert, beide fehlerfrei kompiliert und die erste ohne Fehler ausgeführt. Die zweite hat ein Fehlerfenster geöffnet, aber ich kann mich nicht daran erinnern und kann nicht reproduzieren (im Moment kein Zugriff auf Windows).

Ich habe sie auch unter Linux (Kubuntu 10.10 mit vorkompiliertem Kernel-Paket Version 2.6.35.23.25) mit g ++ ausprobiert und beide kompilieren und ohne Fehler laufen lassen.

Warum? Sollte es keine Pop-ups mit "Falscher Zugriff auf nicht zugeordneten Speicher" geben?

Ich weiß, dass es kompilieren sollte (und zum Glück auch), ohne Fehler, aber ich dachte, es sollte nicht ohne sie laufen ... Und warum das zweite Beispiel macht Fehler unter Windows und nicht unter Linux?

    
silmeth 30.11.2010, 17:45
quelle

5 Antworten

9

Die Verwendung von nicht zugeordnetem Speicher führt zu undefiniertem Verhalten. Sie können keine Erwartungen haben, was passiert, wenn Sie dies selbst auf dem gleichen System und Compiler tun, geschweige denn über verschiedene Kombinationen von Hardware und Compiler.

Das Programm könnte sofort abstürzen, es könnte für eine Weile funktionieren und später fehlschlagen, es könnte sogar scheinen, dass es perfekt funktioniert.

Der Zugriff auf Speicher, den Sie nicht besitzen, ist jedoch immer ein Programmierfehler. Denken Sie nicht an das Aussehen der richtigen Operation, wie "es manchmal funktioniert", denken Sie daran als "Ich habe wirklich Pech und mein Fehler wird nicht schnell angezeigt".

    
Steve Townsend 30.11.2010, 18:16
quelle
7

Während die anderen Antworten, mit Ausnahme von Mark, nicht falsch sind, sind sie auch nicht genau richtig. Was Sie tun, indem Sie auf Daten zugreifen, die nach dem Ende dessen liegen, was Sie explizit in Ihrem Programm zugewiesen haben, verursacht "undefiniertes Verhalten". Es kann alles tun, einschließlich "Arbeit".

Steves Antwort existierte nicht als ich anfing dies zu schreiben.

    
Crazy Eddie 30.11.2010 18:17
quelle
5

Beide haben einen Array-Zugriff außerhalb der Grenzen - Sie haben ein Array von 3 Float-Pointern und greifen auf das 8. Array zu. Dies wird zwangsläufig zum Absturz bringen.

Im Gegensatz zu Java oder einigen anderen verwalteten Sprachen gibt es jedoch keine explizite Begrenzung für jeden Array-Zugriff (da die damit verbundenen Performance-Kosten unerschwinglich sind). Die einzige Grenze, die Sie überprüfen, ist Ihre MMU. Wenn Sie auf Speicher zugreifen, der nicht zu Ihrer Anwendung gehört, stürzen Sie ab. Wenn Sie auf Speicher stoßen, der nicht zugeordnet ist, aber dennoch Teil Ihres Prozesses ist (z. B. ein Wachwort), wird dies ohne weiteres gelingen. Dies ist ein großartiges Rezept für sehr schwer aufzuspürende Fehler.

Überprüfungen sind der Schlüssel. Tu es wann immer du kannst.

    
EboMike 30.11.2010 17:48
quelle
1

Im ersten Beispiel hat die Registerkarte [2] einen Wert, der auf einen gültigen Speicher zeigt. Registerkarte [2] +7 ist nicht zugeordnet, aber es könnte sein. Kein Seg-Fehler.

In der zweiten, Registerkarte [7] hat keinen Wert ... es ist zufällige Bits (möglicherweise Nullen, oder 0xDEADBEEF oder nur was Wert war dort zuletzt). Dies weist fast sicher nicht auf Speicher hin, der für diese Anwendung gültig ist. Also: Boom.

    
Mark Storer 30.11.2010 17:49
quelle
0

Der Speicherzugriffsschutz ist nicht sehr feinkörnig. Wenn Sie etwas Speicher reservieren, erhalten Sie eine ganze Seite Speicher, der Ihrem Programm zugewiesen ist. Wenn Sie versuchen, auf diesen zusätzlichen Speicher zuzugreifen, ist es wahrscheinlich erfolgreich, aber Sie werden wahrscheinlich auch anderen Speicher überlasten, der Ihrem Programm zugewiesen ist.

Aus diesem Grund funktionieren Pufferüberläufe wie ein Angriff. In vielen Fällen ist vorhersagbar, welchen zusätzlichen Speicher nach der Verwendung des Arrays benötigt wird. Wenn ich kontrollieren kann, was Sie dort eingeben, kann ich Daten überschreiben, die Sie nicht überschreiben wollen. Wenn ich Ihren Call-Stack überschreiben kann, kann ich in Ihrem Prozesskontext beliebigen Code ausführen. Wenn dies ein Dienst ist, der als Administrator ausgeführt wird, habe ich eine Eskalation für lokale Berechtigungen. Wenn es sich um einen internetbezogenen Dienst handelt, habe ich einen Remote-Ausführungsangriff.

Am besten arbeiten Sie mit robusteren Strukturen wie std :: vector, es sei denn, Sie haben einen bestimmten Verwendungszweck für Arrays. (Und selbst dann könnten Sie weg mit Vektoren ).

    
Eclipse 30.11.2010 17:50
quelle