2010-02-10 14 views
25

Ich weiß, wie Sie eine .map-Datei erstellen, um Zugriffsverletzungsfehler aufzuspüren, wenn die Fehlermeldung eine tatsächliche Adresse enthält.So erkennen Sie die Zugriffsverletzung "bei Adresse 00000000"

Aber was, wenn die Fehlermeldung

Access violation at address 00000000. Read of address 00000000. 

sagt, wo ich für die Ursache dieses Problems Sie suchen beginnen ...?

+1

Das hat mich von unter Turbo C erinnert, „Null-Zeiger-Zuordnung“, wenn es in der falschen Art und Weise verwaltet ... – t0mm13b

+3

Ist es reproduzierbar? Ist dies nicht der Fall, fügen Sie ein Tool wie madExcept hinzu und warten Sie auf Fehlerberichte. Verwenden Sie andernfalls den Debugger und schauen Sie sich den Stack-Trace an. –

+0

Dies ist von den alten Turbo C Tage, unter dem Debugger, Hinzufügen einer Uhr zu der Zeiger-Variable auf den Ort 0, die gerade ausgeführte Zeile beim Einstieg, die die Zeigervariable zeigte auf Position 0 Änderungswert ist die Zeile, die verursacht durcheinander. Meistens ein Zeigerfehler ... – t0mm13b

Antwort

27

Eine Zugriffsverletzung in der Nähe der Adresse '00000000' zeigt einen Nullzeigerzugriff an. Du verwendest etwas, bevor es jemals erstellt wurde, höchstwahrscheinlich oder nachdem es FreeAndNil() 'd war.

Oft wird dies durch den Zugriff auf eine Komponente an der falschen Stelle während der Formularerstellung verursacht, oder indem Ihr Hauptformular versucht, auf etwas in einem Datamodul zuzugreifen, das noch nicht erstellt wurde.

MadExcept macht es ziemlich einfach, diese Dinge zu verfolgen, und ist kostenlos für nicht-kommerzielle Nutzung. (Eigentlich ist eine Lizenz für kommerzielle Nutzung auch ziemlich preiswert und das Geld wert.)

+4

Ich markiere dies als die "richtige" Antwort, da der Tipp über MadExcept sehr nützlich war. Es scheint jedoch, dass der Fehler in meinem speziellen Fall in einer Drittanbieter-Bibliothek passiert (und hoffentlich durch einen Anbieter-Patch behoben werden kann), so dass ich dieses Mal nicht weiter recherchieren musste. – ObiWanKenobi

+0

Das bedeutet, dass das Objekt, auf das Sie sich bewerben, bereits zerstört ist oder noch nicht erstellt wurde – Kutsoff

1

Wahrscheinlich liegt es daran, dass Sie direkt oder indirekt über einen Bibliotheksaufruf auf einen NULL-Zeiger zugreifen. In diesem speziellen Fall sieht es so aus, als wären Sie auf eine NULL-Adresse gesprungen, die etwas b-haariger ist.

Meiner Erfahrung nach ist der einfachste Weg, diese zu verfolgen, es mit einem Debugger auszuführen und einen Stack-Trace zu speichern.

Alternativ können Sie es tun „von Hand“ und viele Protokollierung hinzufügen, bis Sie genau die Spur können, welche Funktion (und möglicherweise LOC) diese Verletzung aufgetreten ist in.

Werfen Sie einen Blick auf Stack Tracer, die helfen könnten Sie verbessern Ihr Debugging.

7

Sie beginnen in der Nähe von diesem Code suchen, der Sie wissen lief, und Sie suchen nicht mehr, wenn Sie den Code erreichen Sie wissen nicht ausgeführt wurde.

Was Sie suchen, ist wahrscheinlich ein Ort, wo Ihr Programm eine Funktion durch einen Funktionszeiger aufruft, aber dieser Zeiger ist null.

Es ist auch möglich, dass Sie Stapel Korruption haben. Möglicherweise haben Sie die Rückgabeadresse einer Funktion mit Null überschrieben, und die Ausnahme tritt am Ende der Funktion auf. Suchen Sie nach möglichen Pufferüberläufen, und wenn Sie DLL-Funktionen aufrufen, vergewissern Sie sich, dass Sie die richtige Aufrufkonvention und die richtige Anzahl von Parametern verwendet haben.

Dies ist kein gewöhnlicher Fall der Verwendung eines Null-Zeigers, wie ein nicht zugewiesener Objektreferenz oder PChar. In diesen Fällen haben Sie einen Wert ungleich 0 "bei Adresse x". Da der Befehl an der Adresse Null aufgetreten ist, wissen Sie, dass der Befehlszeiger der CPU nicht auf eine gültige Anweisung zeigt. Aus diesem Grund kann der Debugger Ihnen nicht zeigen, welche Codezeile das Problem verursacht hat - dort ist keine Codezeile. Sie müssen es finden, indem Sie den Code finden, der zu der Stelle führte, an der die CPU zu der ungültigen Adresse gesprungen ist.

Der Call-Stack könnte noch intakt sein, was Sie zumindest ziemlich nah an Ihr Ziel bringen sollte. Wenn Sie jedoch eine Stack-Beschädigung haben, können Sie dem Aufruf-Stack möglicherweise nicht vertrauen.

2

Wenn ich auf dieses Problem gestoßen bin, beginne ich normalerweise, die Stellen zu betrachten, wo ich FreeAndNil() oder nur xxx: = NIL; Variablen und der Code danach.

Wenn nichts anderes geholfen hat, habe ich eine Log() -Funktion hinzugefügt, um Nachrichten von verschiedenen verdächtigen Orten während der Ausführung auszugeben, und dann später in diesem Protokoll nachverfolgen, wo im Code die Zugriffsverletzung kommt.

Es gibt natürlich viele elegantere Lösungen für die Verfolgung dieser Verstöße, aber wenn Sie sie nicht zu Ihrer Verfügung haben, funktioniert die altmodische Probe & Fehlermethode gut.

1

Verwenden Sie MadExcept. Oder JclDebug.

1

Ich werde zweite madExcept und ähnliche Tools, wie Eurekalog, aber ich denke, Sie können einen guten Weg mit FastMM auch kommen. Wenn der Debugmodus vollständig aktiviert ist, sollte er Ihnen Hinweise geben, was falsch ist.

Wie auch immer, auch wenn Delphi FastMM als Standard verwendet, lohnt es sich, das volle FastMM für seine zusätzliche Kontrolle über die Protokollierung zu bekommen.

29

Die akzeptierte Antwort erzählt nicht die ganze Geschichte.

Ja, wenn Sie Nullen sehen, ist ein NULL Zeiger beteiligt. Das liegt daran, NULL ist per Definition Null. Also kann NULL nicht viel sagen.

Was interessant über die Nachricht, die Sie erhalten, ist die Tatsache, dass NULL zweimal erwähnt wird. Tatsächlich ähnelt die von Ihnen gemeldete Nachricht ein wenig der Nachricht, die Windows-Betriebssysteme dem Benutzer zeigen.

Die Nachricht sagt der AdresseNULL-versucht lesenNULL. Was bedeutet das? Wie liest sich eine Adresse konkret?

Wir denken typischerweise an die Anweisungen an einer Adresse lesen und schreiben aus dem Speicher an bestimmten Adressen. Wenn wir das wissen, können wir die Fehlermeldung analysieren. Die Nachricht versucht zu artikulieren, dass die Anweisung bei AdresseNULL versucht, lesenNULL.

Natürlich gibt es keine Anweisung bei Adresse NULL, deshalb denken wir an NULL als speziell in unserem Code. Aber jede Instruktion kann so verstanden werden, als würde sie mit dem Versuch beginnen, sich selbst zu lesen. Wenn das CPU-Register EIP auf der Adresse NULL ist, versucht die CPU, den Opcode für eine Anweisung von Adresse 0x00000000 (NULL) zu lesen. Dieser Versuch, NULL zu lesen, schlägt fehl und generiert die Nachricht, die Sie erhalten haben.

Beachten Sie im Debugger, dass EIP gleich 0x00000000 ist, wenn Sie diese Nachricht erhalten. Dies bestätigt die Beschreibung, die ich Ihnen gegeben habe.

Die Frage wird dann, "warum versucht mein Programm, die NULL Adresse auszuführen."Es gibt drei Möglichkeiten, die in den Sinn.

  • Sie versucht haben, einen Funktionsaufruf über einen Funktionszeiger zu machen, die Sie deklariert haben, zugewiesen NULL, sonst nie initialisiert und werden dereferencing
  • Ähnlich Sie können eine "abstrakte" C++ - Methode aufrufen, die einen NULL-Eintrag in der Vtable des Objekts hat. Diese werden in Ihrem Code mit der Syntax erstellt.
  • In Ihrem Code wurde ein Stapelpuffer beim Schreiben von Nullen übergelaufen wurden über das Ende des Stapelpuffers geschrieben, über die beibehaltene Rücksprungadresse, wenn die Funktion später ihren 012 ausführtwird der Wert 0x00000000 (NULL) aus dem überschriebenen Speicherbereich geladen. Diese Art von Fehler, Stack-Overflow, ist der Namensgeber unseres Forums.

Da Sie erwähnen, dass Sie ein Drittanbieter-Bibliothek aufrufen, werde ich darauf hinweisen, dass es sich um eine Situation der Bibliothek sein kann, erwarten Sie einige API eine nicht NULL Funktionszeiger als Eingabe zur Verfügung zu stellen. Diese werden manchmal als "Rückruf" -Funktionen bezeichnet.

Sie müssen den Debugger verwenden, um die Ursache Ihres Problems weiter einzuschränken, aber die oben genannten Möglichkeiten sollten Ihnen helfen, das Rätsel zu lösen.

3

Wenn Sie 'Zugriffsverletzung bei Adresse 00000000.' erhalten, rufen Sie einen Funktionszeiger auf, der nicht zugewiesen wurde - möglicherweise ein Ereignishandler oder eine Rückruffunktion.

zum Beispiel

type 
TTest = class(TForm); 
protected 
    procedure DoCustomEvent; 
public 
    property OnCustomEvent : TNotifyEvent read FOnCustomEvent write FOnCustomEvent; 
end; 

procedure TTest.DoCustomEvent; 
begin 
    FOnCustomEvent(Self); 
end; 

Statt

procedure TTest.DoCustomEvent; 
begin 
    if Assigned(FOnCustomEvent) then // need to check event handler is assigned! 
    FOnCustomEvent(Self); 
end; 

Wenn der Fehler in einem Dritten Komponente ist, und Sie können Sie den fehlerhaften Code verfolgen, verwenden Sie einen leeren Ereignishandler das AV zu verhindern .

-1

Hier ist eine echte schnelle temporäre Lösung, zumindest bis Sie wieder neu starten, aber es wird einen dauerhaften Zugriff loswerden. Ich hatte ein Programm installiert, das funktioniert, aber aus irgendeinem Grund gibt es einen Punkt, der nicht korrekt in der richtigen Datei installiert wurde. Wenn es also nicht auf die Datei zugreifen kann, wird der Zugriff verweigert, aber anstatt nur einen zu versuchen, versucht es, es zu starten. Selbst wenn nach dem Ort gesucht wird, an dem es dauerhaft gestoppt werden kann, wird es immer mehr und mehr auftauchen 3 Sekunden. Zu stoppen, die von zumindest zeitweise geschieht, gehen Sie wie folgt ...

  1. Ctl + Alt + Del
  2. Öffnen Sie den Task-Manager
  3. Notieren Sie den Namen des Programms, das ist Zugriff anfordern (möglicherweise auf der Registerkarte Ihrer Anwendung)
  4. Klicken Sie auf die Registerkarte Prozesse
  5. Scrollen Sie durch, bis Sie die Prozessabgleich finden die Programmnamen und klicken Sie darauf
  6. Klicken Sie auf Prozess beenden

, dass das Fenster von anhaltend Aufspringen, zumindest bis zum Neustart verhindern.Ich weiß, dass das das Problem nicht löst, aber wie bei allem gibt es einen Prozess der Eliminierung und dieser Schritt hier wird es zumindest etwas weniger nervig machen.

Verwandte Themen