Domanda

Come procederesti al rilevamento del codice morto nel codice C / C ++? Ho una base di codice piuttosto grande con cui lavorare e almeno il 10-15% è codice morto. Esiste uno strumento basato su Unix per identificare queste aree? Alcuni pezzi di codice usano ancora molto preprocessore, un processo automatizzato può gestirlo?

È stato utile?

Soluzione

È possibile utilizzare uno strumento di analisi della copertura del codice per questo e cercare punti non utilizzati nel codice.

Uno strumento popolare per la toolchain di gcc è gcov, insieme al frontend grafico lcov ( http: / /ltp.sourceforge.net/coverage/lcov.php ).

Se usi gcc, puoi compilare con il supporto gcov, che è abilitato dal flag '--coverage'. Quindi, esegui l'applicazione o esegui la suite di test con questa build abilitata per gcov.

Fondamentalmente gcc emetterà alcuni file extra durante la compilazione e l'applicazione emetterà anche alcuni dati di copertura durante l'esecuzione. Devi raccogliere tutti questi (file .gcdo e .gcda). Non sto andando in dettaglio qui, ma probabilmente è necessario impostare due variabili di ambiente per raccogliere i dati di copertura in modo sano: GCOV_PREFIX e GCOV_PREFIX_STRIP ...

Dopo l'esecuzione, è possibile riunire tutti i dati di copertura ed eseguirli tramite lcov toolsuite. È anche possibile unire tutti i file di copertura da diverse esecuzioni di test, anche se un po 'coinvolti.

In ogni caso, si finisce con un bel set di pagine Web che mostrano alcune informazioni sulla copertura, sottolineando le parti di codice che non hanno copertura e quindi non sono state utilizzate.

Ovviamente, devi ricontrollare se le porzioni di codice non sono usate in nessuna situazione e molto dipende da quanto bene i tuoi test esercitano la base di codice. Ma almeno, questo darà un'idea sui possibili candidati con codice morto ...

Altri suggerimenti

Compilalo sotto gcc con -Wunreachable-code.

Penso che più recente è la versione, migliori saranno i risultati, ma potrei sbagliarmi nella mia impressione che sia qualcosa su cui stanno lavorando attivamente. Tieni presente che questo analizza il flusso, ma non credo che ti dica di " codice " che è già morto quando lascia il preprocessore, perché non è mai stato analizzato dal compilatore. Inoltre non rileverà ad es. funzioni esportate che non vengono mai chiamate, o codici di gestione di casi speciali che risultano così impossibili perché nulla chiama mai la funzione con quel parametro - per questo è necessaria una copertura del codice (ed eseguire i test funzionali, non i test unitari. I test unitari sono suppone di avere una copertura del codice del 100%, e quindi eseguire percorsi di codice che sono "morti" per quanto riguarda l'applicazione). Tuttavia, con queste limitazioni in mente, è un modo semplice per iniziare a trovare le routine più completamente bollixed nella base di codice.

Questo avviso CERT elenca alcuni altri strumenti per il rilevamento di codice morto statico

Il tuo approccio dipende dai test di disponibilità (automatizzati). Se disponi di una suite di test di cui ti fidi per coprire una quantità sufficiente di funzionalità, puoi utilizzare un'analisi di copertura, come già suggerito dalle risposte precedenti.

Se non sei così fortunato, potresti voler esaminare gli strumenti di analisi del codice sorgente come SciTools "Comprendi che può aiutarti ad analizzare il tuo codice utilizzando molti rapporti di analisi integrati. La mia esperienza con questo strumento risale a 2 anni fa, quindi non posso darvi molti dettagli, ma quello che ricordo è che avevano un supporto impressionante con tempi di consegna molto rapidi di correzioni di bug e risposte a domande.

Ho trovato una pagina su analisi del codice sorgente statico che elenca anche molti altri strumenti.

Se neanche questo ti aiuta a sufficienza e sei particolarmente interessato a scoprire il codice morto relativo al preprocessore, ti consiglio di pubblicare alcuni dettagli in più sul codice. Ad esempio, se è principalmente correlato a varie combinazioni di impostazioni #ifdef, è possibile scrivere script per determinare le (combinazioni di) impostazioni e scoprire quali combinazioni non vengono mai effettivamente create, ecc.

g ++ 4.01 -Wunreachable-code avverte del codice che non è raggiungibile all'interno di una funzione, ma non avvisa delle funzioni non utilizzate.

int foo() { 
    return 21; // point a
}

int bar() {
  int a = 7;
  return a;
  a += 9;  // point b
  return a;
}

int main(int, char **) {
    return bar();
}

g ++ 4.01 emetterà un avviso sul punto b, ma non dice nulla su foo () (punto a) anche se non è raggiungibile in questo file. Questo comportamento è corretto sebbene deludente, poiché un compilatore non può sapere che la funzione foo () non è dichiarata esternamente in qualche altra unità di compilazione e invocata da lì; solo un linker può essere sicuro.

Solo per il codice C e presupponendo che sia il codice sorgente dell'intero progetto è disponibile, avvia un'analisi con lo strumento Open Source Frama-C . Qualsiasi istruzione del programma visualizzata in rosso nella GUI lo è codice morto.

Se hai " codice morto " problemi, potrebbe interessarti anche rimuovendo il "codice di riserva", il codice che viene eseguito ma non lo fa contribuire al risultato finale. Questo richiede di fornire un'accurata modellizzazione delle funzioni I / O (non si vorrebbe per rimuovere un calcolo che sembra essere "di riserva" ma che viene utilizzato come argomento per printf ). Frama-C ha un'opzione per indicare il codice di riserva.

Entrambi Mozilla e Open Office hanno soluzioni di produzione propria.

Un'analisi del codice morto come questa richiede un'analisi globale dell'intero progetto. Non puoi ottenere queste informazioni analizzando le unità di traduzione singolarmente (bene, puoi rilevare entità morte se sono interamente all'interno di una singola unità di traduzione, ma non penso che sia quello che stai davvero cercando).

Abbiamo usato il nostro DMS Software Reengineering Toolkit per implementare esattamente questo per il codice Java, analizzando tutte le unità di compilazione coinvolte contemporaneamente, costruendo tabelle di simboli per tutto e inseguendo tutti i riferimenti. Una definizione di livello superiore senza riferimenti e nessuna rivendicazione di essere un elemento API esterno è morta. Questo strumento inoltre elimina automaticamente il codice morto e alla fine puoi scegliere quello che vuoi: il rapporto delle entità morte o il codice rimosso da tali entità.

DMS analizza anche C ++ in una varietà di dialetti (EDIT febbraio 2014: comprese le versioni MS e GCC di C ++ 14 [EDIT Nov 2017: ora C ++ 17] ) e crea tutte le tabelle dei simboli necessarie. Rintracciare i riferimenti morti sarebbe semplice da quel punto. DMS potrebbe anche essere usato per eliminarli. Vedi http://www.semanticdesigns.com/Products/DMS/DMSToolkit.html

Lo strumento di copertura

Bullseye sarebbe di aiuto. Non è gratuito però.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top