Bearbeiten

FAQs zum Debuggen von nativem Code

Wie kann ich Zugriffsverstöße debuggen, wenn ich mein Programm außerhalb des Visual Studio-Debuggers ausführe?

Legen Sie die Option für das Just-In-Time-Debuggen fest, und führen Sie das Programm im eigenständigen Modus aus, bis eine Zugriffsverletzung auftritt. Dann können Sie im Dialogfeld Zugriffsverletzung auf Abbrechen klicken, um den Debugger zu starten.

Wie erfolgt das Debuggen bei einem C++-Zugriffsverstoß?

Wenn eine Zugriffsverletzung bei einer Codezeile auftritt, in der mehrere Zeiger dereferenziert werden, kann es schwierig sein, zu ermitteln, welcher Zeiger die Zugriffsverletzung verursacht hat. In Visual Studio benennt das Dialogfeld für Ausnahmen explizit den Zeiger, der den Zugriffsverstoß verursacht hat.

Beispielsweise sollte der folgende Code zu einer Zugriffsverletzung führen:

#include <iostream>
using namespace std;

class ClassC {
public:
  void printHello() {
    cout << "hello world";
  }
};

class ClassB {
public:
  ClassC* C;
  ClassB() {
    C = new ClassC();
  }
};

class ClassA {
public:
  ClassB* B;
  ClassA() {
    // Uncomment to fix
    // B = new ClassB();
  }
};

int main() {
  ClassA* A = new ClassA();
  A->B->C->printHello();

}

Wenn Sie diesen Code in Visual Studio ausführen, sollte das folgende Ausnahmedialogfeld angezeigt werden:

Screenshot of a Microsoft Visual Studio exception dialog, showing a read access violation for 'A->B was nullptr'. The Break button is selected.

Wenn Sie nicht bestimmen können, warum der Zeiger eine Zugriffsverletzung verursacht hat, überwachen Sie den Code mithilfe der Ablaufverfolgung, um sicherzustellen, dass der Zeiger, der das Problem verursacht, ordnungsgemäß zugewiesen wurde. Wenn er als Parameter übergeben wird, achten Sie darauf, dass die Übergabe ordnungsgemäß erfolgt und Sie nicht versehentlich eine flache Kopie erstellen. Vergewissern Sie sich anschließend, dass die Werte nicht unbeabsichtigt im Programm geändert werden. Erstellen Sie zu diesem Zweck einen Datenhaltepunkt für den fraglichen Zeiger. So sorgen Sie dafür, dass er nicht an anderer Stelle im Programm geändert wird. Weitere Informationen zu Datenhaltepunkten finden Sie im Abschnitt über Datenhaltepunkte in Using Breakpoints.

Wie wird festgestellt, ob Zeiger eine Speicheradresse zerstören?

Überprüfen Sie den Heap auf Beschädigungen. Ein Speicherschaden ist die Folge einer Heapbeschädigung. Verwenden Sie in diesem Fall das Global Flags-Dienstprogramm (gflags.exe) oder "pageheap.exe". Siehe /windows-hardware/drivers/debugger/gflags-and-pageheap.

So finden Sie die geänderte Stelle der Speicheradresse

  1. Legen Sie einen Datenhaltepunkt bei 0x00408000 fest. Weitere Informationen finden Sie unter Set a data change breakpoint (native C++ only) (Festlegen eines Haltepunkts für Datenänderungen (nur nativer C++-Code)).

  2. Zeigen Sie den Speicherinhalt bei Erreichen eines Haltepunkts im Fenster Speicher ab Adresse 0x00408000 an. Weitere Informationen finden Sie unter Arbeitsspeicherfenster.

Wie wird festgestellt, woher der falsche Parameterwert stammt?

Dieses Problem lässt sich wie folgt beheben:

  1. Legen Sie am Anfang der Funktion einen Positionshaltepunkt fest.

  2. Klicken Sie mit der rechten Maustaste auf den Haltepunkt, und wählen Sie Bedingung aus.

  3. Aktivieren Sie im Dialogfeld Bedingung für Haltepunkt das Kontrollkästchen Bedingung. Siehe Erweiterte Haltepunkte.

  4. Geben Sie einen Ausdruck, z. B. Var==3, in das Textfeld ein, wobei Var der Name des Parameters ist, der den falschen Wert enthält, und 3 der übergebene falsche Wert.

  5. Aktivieren Sie das Optionsfeld is True (ist TRUE), und klicken Sie auf die Schaltfläche OK.

  6. Führen Sie nun das Programm erneut aus. Der Haltepunkt bewirkt, dass das Programm am Funktionsanfang anhält, sobald Var den Wert 3 hat.

  7. Im Fenster Aufrufliste sehen Sie die aufrufende Funktion und können zu ihrem Quellcode navigieren. Weitere Informationen finden Sie unter Vorgehensweise: Use the Call Stack Window (Vorgehensweise: Verwenden des Fensters Aufrufliste).

Wie kann festgestellt werden, bei welchem Aufruf ein Fehler aufgetreten ist, wenn eine Funktion sehr häufig aufgerufen wird?

Beispiel: Das Programm schlägt bei einem Aufruf einer bestimmten Funktion mit dem Namen CnvtV fehl. Zuvor hat das Programm die Funktion jedoch mehrere Hundert Male aufgerufen. Wenn ein Positionshaltepunkt für CnvtV festgelegt wird, hält das Programm bei jedem Aufruf der Funktion an, was nicht beabsichtigt ist. Da nicht bekannt ist, welche Bedingungen den fehlschlagenden Aufruf verursachen, kann kein bedingter Haltepunkt festgelegt werden. Welche Möglichkeiten gibt es?

Mithilfe des Felds Trefferanzahl können Sie einen Haltepunkt für die Funktion auf einen hohen Wert festlegen, der niemals erreicht wird. Da Sie davon ausgehen, dass die CnvtV-Funktion einige Hundert Male aufgerufen wird, könnten Sie Trefferanzahl auf einen Wert von mindestens 1000 festlegen. Führen Sie dann das Programm aus, und warten Sie, bis der Aufruf fehlschlägt. Sobald dies der Fall ist, öffnen Sie das Fenster "Haltepunkte" und überprüfen die Haltepunktliste. Der für CnvtV festgelegte Haltepunkt wird, gefolgt von der Trefferanzahl und der Anzahl der noch verbleibenden Iterationen, angezeigt:

CnvtV(int) (no condition) when hit count is equal to 1000 (currently 101)

Jetzt wissen Sie, dass die Funktion bei Aufruf Nr. 101 fehlgeschlagen ist. Wenn Sie nun den Haltepunkt auf eine Trefferanzahl von 101 zurücksetzen und das Programm erneut ausführen, hält es an dem CnvtV-Aufruf an, der zuvor den Fehler verursacht hat.

Wo sind die Win32-Fehlercodes zu finden?

WINERROR.H im Verzeichnis INCLUDE der Standardsysteminstallation enthält die Definitionen der Fehlercodes für die Win32-API-Funktionen.

Sie können den Fehlercode nachsehen, indem Sie den Code im Überwachungsfenster oder im Dialogfeld Schnellüberwachung eingeben. Zum Beispiel:

0x80000004,hr

Wie kann der Fokus beim Durchlaufen der App beibehalten werden?

Beispiel: Das Programm hat Probleme mit der Aktivierung von Fenstern. Beim Durchlaufen des Programms mit dem Debugger kann das Problem nicht reproduziert werden, da das Programm den Fokus verliert. Gibt es eine Möglichkeit, den Fokus nicht zu verlieren?

Wenn Sie über einen zweiten Computer verfügen, verwenden Sie das Remotedebuggen. Sie können das Programm auf dem Remotecomputer verwenden, während der Debugger auf dem Host ausgeführt wird. Weitere Informationen finden Sie unter Vorgehensweise: Auswählen eines Remotecomputers.

Wie können Funktionen der Windows-API gedebuggt werden?

So legen Sie einen Haltepunkt für eine Windows API-Funktion mit NT-Symbolen fest

  • Geben Sie in den Haltepunkt der Funktion die Namen der Funktion und der DLL ein, in der sich die Funktion befindet (siehe den Kontextoperator). Verwenden Sie im 32-Bit-Code die ergänzte Form des Funktionsnamens. Zum Festlegen eines Breakpoints für MessageBeep müssen Sie z. B. Folgendes eingeben:

    {,,USER32.DLL}_MessageBeep@4
    

    Informationen zum Abrufen des ergänzten Namens finden Sie unter Anzeigen von ergänzten Namen.

    Sie können den ergänzten Namen testen und ihn im Disassemblycode anzeigen. Während die Funktion im Visual Studio-Debugger angehalten ist, klicken Sie im Code-Editor oder im Aufruflistenfenster mit der rechten Maustaste auf die Funktion, und wählen Sie Gehe zu Disassembly.

  • In 64-Bit-Code können Sie den nicht ergänzten Namen verwenden.

    {,,USER32.DLL}MessageBeep
    

Nächste Schritte

Unter diesen Links erfahren Sie mehr über das Debuggen von nativem Code in Visual Studio: