Ho visto una pubblicazione che PVS aveva imparato ad analizzare sotto Linux e ho deciso di provarla sui miei progetti. E questo è quello che ne è venuto fuori.
Ho richiesto una chiave di prova e me l'hanno inviata lo stesso giorno.
Documentazione abbastanza chiara
Siamo riusciti ad avviare l'analizzatore senza problemi. È disponibile anche la guida per i comandi della console (sebbene ci siano alcune lamentele qui, vedere la sezione Contro).
Possibilità di analisi multi-thread
L'analizzatore ha un'opzione "standard". -j, consentendo di svolgere l'analisi in parallelo in diversi compiti. Ciò consente di risparmiare molto tempo.
Tutta la documentazione è sul loro sito, posso solo dire che se il tuo progetto è realizzato utilizzando CMake, allora tutto è molto semplice.
Buone descrizioni diagnostiche
Se generi output in modalità fullhtml, quindi ogni messaggio ha un collegamento a una descrizione diagnostica, con spiegazioni, esempi di codici e collegamenti aggiuntivi.
Ignoranza del linguaggio C++ da parte dell'analizzatore
Sfortunatamente, PVS a volte commette errori di sintassi e genera messaggi falsi positivi quando il codice è completamente corretto.
Ad esempio, c'è una funzione che restituisce void:
template <typename T>
auto copy (const void * source, void * destination)
->
std::enable_if_t
<
std::is_copy_constructible<T>::value
>
{
new (destination) T(*static_cast<const T *>(source));
}
Sì, parola chiave auto Può significare void, ecco a cosa serve auto. Ma PVS ha prodotto i seguenti messaggi:
dynamic_tuple_management.hpp:29:1: error: V591 Non-void function should return a value.
dynamic_tuple_management.hpp:29:1: error: V2542 Function with a non-void return type should return a value from all exit paths.
Sito molto lento
Sì, nell'interfaccia web accanto a ciascun messaggio è presente un collegamento alla corrispondente descrizione diagnostica con esempi. Ma quando si fa clic su un collegamento, è necessario attendere parecchio tempo e talvolta ciò accade Timeout gateway 504.
lingua
Tutte le descrizioni sono in russo, il che è fantastico. Ma i collegamenti del rapporto portano sempre alla versione inglese. Sarebbe bello poter cambiare la lingua in modo da poter visualizzare immediatamente la diagnostica in russo. Non ho trovato tale opzione nell'interfaccia.
È scomodo lavorare con i livelli diagnostici tramite la console
Partiamo dal fatto che i due comandi utilizzati (this pvs-studio-analyzer и plog-converter) formati diversi per specificare la diagnostica.
Aiuto per pvs-studio-analyzer si legge:
-a [MODE], --analysis-mode [MODE]
MODE defines the type of warnings:
1 - 64-bit errors;
2 - reserved;
4 - General Analysis;
8 - Micro-optimizations;
16 - Customers Specific Requests;
32 - MISRA.
Modes can be combined by adding the values
Default: 4
Ho passato molto tempo cercando di capire dove andare aggiungere (“somma dei valori”). Ho provato ad elencarli separati da virgole:
pvs-studio-analyzer analyze ... -a 1,4,16
Ho provato a registrare la chiave più volte:
pvs-studio-analyzer analyze ... -a 1 -a 4 -a 16
E solo allora ho capito che si trattava di piccole maschere! E hai bisogno riassumereE non aggiungere significati. Ad esempio, per ottenere la diagnostica generale, la diagnostica per le micro-ottimizzazioni e MISRA, è necessario sommarle (4 + 8 + 32 = 44):
pvs-studio-analyzer analyze ... -a 44
L'uso delle maschere di bit nelle interfacce utente è generalmente una cattiva forma. Tutto ciò potrebbe essere riepilogato internamente e una serie di flag potrebbe essere impostata per l'utente.
Inoltre, c'è anche un'utilità plog-converter, che genera informazioni di analisi statica leggibili dall'uomo. Ha altri problemi.
Aiuto per il programma plog-converter rapporti:
-a, --analyzer Specifies analyzer(s) and level(s) to be
used for filtering, i.e.
'GA:1,2;64:1;OP:1,2,3;CS:1;MISRA:1,2'
Default: GA:1,2
Qui sono apparsi alcuni "livelli" che prima non c'erano e non ho trovato nulla nemmeno nella documentazione a riguardo.
In generale, non è chiaro. Ecco perché ho impostato tutto al massimo.
Un mucchio di stupide imprecazioni su Catch
Due dei tre progetti che ho analizzato utilizzano una libreria di unit test Catch2. E la maggior parte dei messaggi (!!! 90 su 138 in uno e 297 su 344 nell'altro!!!) hanno la seguente forma:
Non tiene conto del multithreading
Esistono molti falsi positivi su variabili apparentemente immutabili o cicli infiniti, mentre il lavoro con queste variabili avviene da thread diversi e, se così non fosse, i test unitari non funzionerebbero.
Tuttavia, un analizzatore statico può tenerne conto? Non lo so.
PVS non ha riscontrato alcun bug reale nei miei progetti open source scoppiare и Il prossimo, nonché in un progetto di lavoro che, per ovvi motivi, non posso presentare. È vero, vale la pena tenere presente che alcune carenze sono già state individuate e corrette in precedenza Cppcheck и scan-build.
In generale, l'impressione di tutti questi analizzatori è più o meno la stessa: sì, catturano qualcosa, a volte anche qualcosa di importante, ma nel complesso è sufficiente il compilatore.
È possibile (e personalmente mi piace pensarlo) che il nostro team utilizzi pratiche di sviluppo software che ci consentono di generare una quantità minima di codice di merda. È meglio non creare problemi che superarli eroicamente.
Mi permetto quindi di dare qualche consiglio su come scrivere in C++ in modo tale da non sparare alle gambe a nessuno o colpire qualcuno in fronte con un rastrello.
Ottieni il massimo dalla diagnostica del compilatore
Il nostro team utilizza (e ti consiglia di farlo) le seguenti opzioni di compilazione:
Abilitali nel tuo progetto e impara molto sul tuo codice.
Attenersi allo standard
Cerca di non utilizzare cose dipendenti dalla piattaforma se ci sono analoghi standard e, se non puoi assolutamente farne a meno, avvolgili in blocchi speciali per macro (o qualcos'altro) e semplicemente non lasciare che il tuo codice venga compilato in condizioni non supportate.
Attenersi alla semantica operativa standard
L'addizione deve essere addizione, la moltiplicazione deve essere moltiplicazione, la chiamata di funzione deve essere chiamata di funzione, la copia deve essere copia, il riporto deve essere riporto, il contenitore deve essere iterabile, l'iteratore deve avere una promozione ++ e dereferenziazione *. E così via e così via.
Penso che l'idea sia chiara. Esistono convenzioni stabilite che non sono vincolanti, ma che tutti gli utenti e lettori del tuo codice si aspettano di vedere. Non cercare di superare in astuzia gli altri, altrimenti supererai te stesso.
Scrivi codice compatibile
Prima di tutto, intendo la libreria standard. È altamente auspicabile che le interfacce delle classi e delle funzioni possano essere utilizzate con librerie standard e di altro tipo (ad esempio Boost).
Sentiti libero di dare un'occhiata alle interfacce STL e Boost. Con rare eccezioni, lì vedrai un degno modello.
Ottieni il massimo dagli strumenti open source
Per la stessa analisi statica, ci sono almeno due strumenti gratuiti aperti che possono essere collegati una sola volta a qualsiasi progetto con il sistema di compilazione CMake.
Infine, vorrei sottolineare che non sto consigliando di non utilizzare PVS o altri analizzatori statici. Ma ti incoraggio a pensare a come è successo che l'analizzatore statico trovi costantemente errori significativi nel tuo codice.
Questa è solo una conseguenza. Dobbiamo cercare ed eliminare la causa.