Domande frequenti sul debug del codice nativo

Come è possibile eseguire il debug delle violazioni di accesso quando si esegue il programma all'esterno del debugger di Visual Studio?

Impostare l'opzione Debug JIT ed eseguire il programma autonomamente finché non si verifica la violazione di accesso. Nella finestra di dialogo Violazione di accesso sarà quindi possibile fare clic su Annulla per avviare il debugger.

Come è possibile eseguire il debug di una violazione di accesso C++?

Se si riceve un avviso di violazione di accesso su una riga di codice che dereferenzia più puntatori, può essere difficile individuare il puntatore che ha causato la violazione di accesso. In Visual Studio la finestra di dialogo eccezione assegna un nome esplicito al puntatore che ha causato la violazione di accesso.

Ad esempio, con il codice seguente si dovrebbe ottenere una violazione di accesso:

#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();

}

Se si esegue questo codice in Visual Studio, verrà visualizzata la finestra di dialogo di eccezione seguente:

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

Se non è possibile determinare perché il puntatore ha causato una violazione di accesso, tracciare il codice per assicurarsi che il puntatore che provoca il problema sia stato assegnato correttamente. Se viene passato come parametro, assicurarsi che sia passato in modo corretto e che non si stia creando accidentalmente una copia superficiale. Verificare quindi che i valori non vengano involontariamente modificati in qualche punto del programma creando un punto di interruzione dei dati per il puntatore in questione per assicurarsi che non venga modificato altrove nel programma. Per ulteriori informazioni sui punti di interruzione dei dati, vedere la relativa sezione in Using Breakpoints.

Come è possibile stabilire se i puntatori danneggiano un indirizzo di memoria?

Verificare la presenza di danneggiamento dell'heap. La maggior parte del danneggiamento della memoria è dovuta al danneggiamento dell'heap. Provare a utilizzare l'utilità per i flag globali (gflags.exe) o pageheap.exe. Vedere /windows-hardware/drivers/debugger/gflags-and-pageheap.

Per trovare dove viene modificato l'indirizzo di memoria:

  1. Impostare un punto di interruzione di dati all'indirizzo 0x00408000. Vedere Impostare un punto di interruzione di modifica dei dati (solo C++ nativo).

  2. Quando si raggiunge un punto di interruzione, usare la finestra Memoria per visualizzare il contenuto della memoria a partire dall'indirizzo 0x00408000. Per altre informazioni, vedere Memory Windows.For more information, see Memory Windows.

Come è possibile scoprire chi sta passando un valore di parametro errato?

Per risolvere questo problema:

  1. Impostare un punto di interruzione del percorso all'inizio della funzione.

  2. Fare clic con il pulsante destro del mouse sul punto di interruzione e scegliere Condizione.

  3. Nella finestra di dialogo Condizione punto di interruzione selezionare la casella di controllo Condizione. Vedere Punti di interruzione avanzati.

  4. Nella casella di testo immettere un'espressione, ad esempio Var==3, in cui Var è il nome del parametro che contiene il valore errato e 3 il valore errato passato.

  5. Selezionare il pulsante di opzione è true, quindi scegliere OK.

  6. Eseguire nuovamente il programma. Il punto di interruzione causa l'arresto del programma all'inizio della funzione, quando il parametro Var ha valore 3.

  7. Utilizzare la finestra Stack di chiamate per individuare la funzione chiamante e passare al relativo codice sorgente. Per altre informazioni, vedere Procedura: Usare la finestra Stack di chiamate.

Quando vengono effettuate centinaia di chiamate di una funzione, come è possibile trovare la chiamata che ha avuto esito negativo?

Esempio: il programma non riesce in una chiamata a una determinata funzione, CnvtV. Il programma probabilmente chiama tale funzione un paio di centinaia di volte prima di bloccarsi. Impostando un punto di interruzione di posizione su CnvtV, il programma si arresta a ciascuna chiamata a tale funzione e questo non è auspicabile. Non sapendo quali condizioni hanno causato l'esito negativo della funzione, non è possibile impostare un punto di interruzione condizionale. Cosa posso fare?

È possibile impostare un punto di interruzione sulla funzione specificando nel campo Passaggi un valore così alto da non poter essere raggiunto. In questo caso, poiché si ritiene che la funzione CnvtV venga chiamata circa duecento volte, è possibile impostare Passaggi su 1000 o su un valore maggiore. Eseguire quindi il programma e attendere l'arresto della chiamata. A questo punto, aprire la finestra Punti di interruzione ed esaminare l'elenco dei punti di interruzione. Il punto di interruzione impostato per CnvtV è presente nell'elenco ed è seguito dal conteggio di passaggi e dal numero delle iterazioni rimanenti:

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

A questo punto la funzione con esito negativo risulta essere la chiamata 101. Se si reimposta il punto di interruzione con un conteggio di passaggi di 101 e si esegue nuovamente il programma, esso si arresterà in corrispondenza della chiamata a CnvtV che ha causato il blocco.

Come è possibile accedere ai codici di errore di Win32?

WINERROR. H nella directory INCLUDE dell'installazione predefinita del sistema contiene le definizioni del codice di errore per le funzioni API Win32.

È possibile cercare un codice di errore digitando tale codice nella finestra Espressioni di controllo o nella finestra di dialogo Controllo immediato. Ad esempio:

0x80000004,hr

Come è possibile mantenere lo stato attivo durante l'esecuzione dell'app?

Esempio: il programma presenta un problema di attivazione della finestra. L'esecuzione istruzione per istruzione del programma con il debugger interferisce con la possibilità di riprodurre il problema, poiché il programma non mantiene lo stato attivo. Esiste un modo per evitare di perdere lo stato attivo?

Se si dispone di un secondo computer, ricorrere al debug remoto. È possibile eseguire il programma sul computer remoto mentre si esegue il debugger sull'host. Per altre informazioni, vedere Procedura: Selezionare un computer remoto.

Come è possibile eseguire il debug di funzioni API Windows?

Per impostare un punto di interruzione in una funzione API di Windows con simboli NT caricati:

  • Nel punto di interruzione della funzione immettere il nome della funzione insieme al nome della DLL in cui risiede la funzione (vedere l'operatore di contesto). Nel codice a 32 bit, utilizzare la forma decorata del nome della funzione. Ad esempio, per impostare un punto di interruzione su MessageBeep, è necessario immettere quanto segue.

    {,,USER32.DLL}_MessageBeep@4
    

    Per ottenere il nome decorato, vedere Visualizzazione dei nomi decorati.

    È possibile testare il nome decorato e visualizzarlo nel codice disassembly. Durante la sospensione della funzione nel debugger di Visual Studio, fare clic con il pulsante destro del mouse sulla funzione nell'editor di codice o nella finestra dello stack di chiamate e scegliere Vai a Disassembly.

  • Nel codice a 64 bit è possibile usare il nome non dichiarato.

    {,,USER32.DLL}MessageBeep
    

Passaggi successivi

Per altre informazioni sul debug del codice nativo in Visual Studio, vedere i collegamenti seguenti: