Come eseguire efficacemente il debugging manuale? [chiuso]

8

Supponiamo che tu non abbia un debugger disponibile, quale sarebbe un approccio efficace al codice di debug che non funziona (come previsto)?

    
posta Anto 22.02.2011 - 17:17
fonte

9 risposte

7

Esistono diverse tecniche:

  1. Registrazione. Se non si ha accesso ai file, accedere a una console seriale o qualsiasi dispositivo di output disponibile. È una buona idea scrivere sempre il tuo codice tenendo presente la registrazione, consentendo una compilazione condizionale per diversi livelli di registrazione, da 'none' a 'overbloated'.

  2. Riducendolo. Escludi le parti del tuo codice intorno a un punto di errore sospetto uno per uno e analizza ciò che hai fatto quando il bug scompare.

  3. Asserzioni o contratti. È una buona idea riempire il tuo codice di asserzioni fin dall'inizio. Non solo aiutano con il debug, ma fungono anche da documentazione aggiuntiva per il tuo codice.

  4. Simile a 2. - varia il tuo input e mescola il codice a meno che il bug non scompaia o cambi il suo comportamento. È spesso una buona idea giocare con vari livelli di ottimizzazione (se stai codificando in C o C ++), poiché i bug relativi ai puntatori tendono ad essere estremamente volatili nel loro comportamento.

  5. Una versione automatica di 3. - usa il codice instrumentato, ad esempio, esegui il file binario in valgrind.

E ovviamente ci sono molti altri strumenti e trucchi, a seconda della natura del tuo ambiente di esecuzione e del tuo codice.

    
risposta data 22.02.2011 - 18:20
fonte
18

Cerca un collega e spiega dettagliatamente il problema mentre passi sul fastidioso codice passo dopo passo.

Spesso l'atto di spiegare è chiaro sia al tuo collega che a te stesso.

    
risposta data 22.02.2011 - 17:23
fonte
3

Esiste un sistema di registrazione per gestire l'output del programma? C'è almeno una console su cui stampare o file su cui scrivere? L'utilizzo di console o file di registro è un modo per eseguire il debug senza un debugger. Assegna al programma un input tale da sapere quale dovrebbe essere l'output, quindi verifica che l'output funzioni e assicurati che la registrazione ti fornisca molti dettagli del processo. Quindi provare con un input che fornisce l'output sbagliato. si spera che i registri ti forniscano una traccia dettagliata di ciò che è andato storto.

    
risposta data 22.02.2011 - 17:32
fonte
3

Dipende. Ha funzionato prima? Se il codice che prima funzionava si rompeva all'improvviso, quindi dovresti esaminare molto attentamente le modifiche più recenti.

    
risposta data 22.02.2011 - 17:48
fonte
2

1) Fai tutto il necessario per rendere il bug riproducibile al 100% o il più vicino possibile al 100%

2) Traccia il problema, usando printf () o altre funzionalità di registrazione. Questa è un'arte, però, e dipende dalla natura del bug.

Se non hai assolutamente idea della posizione del bug, ma ad esempio sai che una condizione diventa falsa ad un certo punto (lo stato del programma si è rotto - chiamiamoloBroken ()), puoi fare un drill down / ricerca partizione per capire la posizione del problema. Ad esempio, registra il valore di isBroken () all'inizio alla fine dei metodi principali:

void doSomething (void)
{
    printf("START doSomething() : %d\n", isBroken());
    doFoo();
    doBar();
    printf("END doSomething() : %d\n", isBroken());
}

Se nel registro vedi

START doSomething() : 0
END doSomething() : 1

sai che qualcosa è andato storto lì. Quindi rimuovi tutti gli altri codici di registrazione e prova questa nuova versione:

void doSomething (void)
{
    printf("START doSomething() : %d\n", isBroken());
    doFoo();
            printf("AFTER doFoo() : %d\n", isBroken());
    doBar();
    printf("END doSomething() : %d\n", isBroken());
}

Ora nel registro potresti vedere questo

START doSomething() : 0
AFTER doFoo() : 0
END doSomething() : 1

Quindi ora sai doBar () attiva il bug e puoi ripetere la procedura sopra in doBar (). Idealmente, dovrai limitare l'errore a una singola riga.

Naturalmente questo può aiutarti a rivelare i sintomi del bug e non la causa principale - per esempio, trovi un puntatore NULL che non dovrebbe essere NULL, ma perché? È quindi possibile accedere di nuovo, ma controllando una diversa condizione "rotta".

Se hai un crash invece di uno stato rotto, è più o meno lo stesso - l'ultima riga del registro ti dà un suggerimento su dove le cose si infrangono.

    
risposta data 22.02.2011 - 18:58
fonte
2

Dopo che le altre risposte hanno fallito , c'è sempre debugging della ricerca binaria :

  1. Elimina una certa porzione (preferibilmente metà) delle possibili cause (righe di codice, revisioni , input, etc)
  2. Prova a riprodurre nuovamente il problema.
  3. Se il problema persiste, torna al passaggio 1.
  4. Se hai una sola causa (riga di codice, revisione, parte di input, ecc.) lasciata: evviva! Esci dalla procedura.
  5. Altrimenti: ripristina il passaggio 1 e ora elimina la altra metà.
  6. Torna al passaggio 2.

Nota: ovviamente, questa tecnica funziona solo se riesci a riprodurre il problema in modo affidabile.

    
risposta data 02.01.2013 - 09:44
fonte
0

'"Lo strumento di debug più efficace è ancora un pensiero attento, insieme a dichiarazioni di stampa giudicate giudiziose." - Brian Kernighan ' In quel giorno poteva essere vero! Il metodo più efficace è quello di esaminare i test unitari, ma suppongo che tu non ne abbia nessuno.

    
risposta data 22.02.2011 - 18:39
fonte
0

Dipende dal bug.

Se il bug è il tipo di "perché il codice sta facendo A", allora può essere utile mettere alla prova la tua comprensione del codice che circonda la posizione del "codice che fa A". Introduci un nuovo codice che ti aspetti di generare nuovi bug (questo codice dovrebbe farlo fare B, questo dovrebbe farlo fare C). Di solito trovo rapidamente un nuovo codice che genera un comportamento che non mi aspetto. Quindi aspetto pazientemente mentre la mia mente costruisce un modello mentale aggiornato del comportamento del codice in modo che l'ultimo cambiamento abbia un senso, e quindi quel cambiamento del modello mentale di solito spiega perché il codice sta facendo A.

Il secondo caso è stato discusso in dettaglio qui. Dove hai ereditato il codice, non hai un solido modello mentale su come funziona il codice, non hai una buona idea sulla posizione specifica del bug, ecc. In questo caso, drilldown / divide-and- i metodi di conquista con le istruzioni di stampa possono funzionare. E se è sotto controllo del codice sorgente, assicurati di controllare la modifica del codice più recente.

    
risposta data 27.09.2012 - 03:42
fonte
0

Espansione su "Lo strumento di debug più efficace è ancora un pensiero attento, insieme a dichiarazioni di stampa giudicate giudiziose."

Per prima cosa, cerca di restringere il momento in cui si verifica l'errore. Rendi osservabili i sintomi osservabili dall'utente. (ad esempio, alcune modifiche alle stringhe non sono corrette, aggiungi un ciclo che esegue il polling del contenuto dello script e attiva il debug mentre cambia.) Ovviamente se l'errore è un arresto anomalo, aggiungi la gestione segfault.

Quindi prova a restringere il thread se il problema riguarda l'ambiente multi-thread. Assegna a ciascun thread un identificatore e scaricalo quando si verifica l'errore.

Una volta ottenuto il filo, cospargere il codice del thread specificato con printfs copiosamente per inchiodare il punto in cui si trova.

Quindi esegui il backtrace in cui si verifica l'azione effettiva che lo crea (l'azione distruttiva sarà spesso un po 'prima dove i dati danneggiati innescano il problema). Esamina quali strutture / variabili si verificano nelle vicinanze nella memoria, osserva i loop che li riguardano , controlla i punti in cui è stato scritto il valore danneggiato.

Una volta ottenuto il punto che causa il problema, prima di risolverlo, pensa due volte a quale dovrebbe essere il comportamento corretto.

    
risposta data 02.01.2013 - 10:11
fonte

Leggi altre domande sui tag