Revizuire independentă a PVS-Studio (Linux, C++)

Am văzut o publicație pe care PVS a învățat să o analizeze sub Linux și am decis să o încerc în propriile proiecte. Și asta a ieșit din asta.


Conținut

  1. Pro
  2. Contra
  3. Rezultatele
  4. postfață

Pro

Suport receptiv

Am cerut o cheie de probă și mi-au trimis-o în aceeași zi.

Documentație destul de clară

Am reușit să lansăm analizorul fără probleme. Este disponibil și ajutor pentru comenzile consolei (deși există câteva reclamații aici, consultați secțiunea Contra).

Posibilitatea analizei multi-threaded

Analizorul are o opțiune „standard”. -j, permițând efectuarea de analize în paralel în mai multe sarcini. Acest lucru economisește mult timp.

Vizualizare bună

Multe formate de ieșire diferite, de la text la un mic bot web. Interfața web este convenabilă, concisă, cu indicii lângă rândurile din cod și link-uri către descrieri de diagnosticare.

Integrare ușoară în ansamblu

Toată documentația este pe site-ul lor, pot spune doar că dacă proiectul tău este construit folosind CMake, atunci totul este foarte simplu.

Descrieri bune de diagnostic

Dacă generați ieșire în mod fullhtml, apoi fiecare mesaj are un link către o descriere de diagnosticare, cu explicații, exemple de cod și linkuri suplimentare.

Contra

Ignorarea limbajului C++ de către analizator

Din păcate, PVS face uneori erori de sintaxă și generează mesaje fals pozitive atunci când codul este complet corect.

De exemplu, există o funcție care revine 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));
}

Da, cuvânt cheie auto Poate însemna void, pentru asta e Auto. Dar PVS a produs următoarele mesaje:

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.

Site foarte lent

Da, în interfața web lângă fiecare mesaj există un link către descrierea de diagnosticare corespunzătoare cu exemple. Dar când dai clic pe un link, trebuie să aștepți destul de mult și uneori se întâmplă 504 Gateway Time-out.

Limbă

Toate descrierile sunt în rusă, ceea ce este grozav. Dar linkurile din raport conduc întotdeauna la versiunea în limba engleză. Ar fi bine să puteți schimba limba, astfel încât să puteți vizualiza imediat diagnosticele în rusă. Nu am găsit o astfel de opțiune în interfață.

Este incomod să lucrezi cu niveluri de diagnosticare prin consolă

Să începem cu faptul că cele două comenzi utilizate (acest pvs-studio-analyzer и plog-converter) formate diferite pentru specificarea diagnosticelor.

Ajutor pentru pvs-studio-analyzer citeste:

-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

Am petrecut mult timp încercând să-mi dau seama unde să merg adăuga tastele („adăugarea valorilor”). Am încercat să le enumerez separate prin virgule:

pvs-studio-analyzer analyze ... -a 1,4,16

Am încercat să înregistrez cheia de mai multe ori:

pvs-studio-analyzer analyze ... -a 1 -a 4 -a 16

Și abia atunci mi-am dat seama că astea erau măști mici! Și ai nevoie rezumăȘi nu adăuga sensuri. De exemplu, pentru a obține diagnostice generale, diagnostice pentru micro-optimizări și MISRA, trebuie să le însumați (4 + 8 + 32 = 44):

pvs-studio-analyzer analyze ... -a 44

Utilizarea măștilor de biți în interfețele utilizatorului este în general proastă. Toate acestea ar putea fi rezumate intern și un set de steaguri ar putea fi setat pentru utilizator.

În plus, există și o utilitate plog-converter, care generează informații de analiză statică care pot fi citite de om. Ea are alte probleme.

Ajutor pentru program plog-converter rapoarte:

-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

Au apărut aici câteva „nivele” care nu existau înainte și nu am găsit nimic despre ele nici în documentație.

În general, nu este clar. De aceea am pus totul la maxim.

O grămadă de înjurături stupide pe Catch

Două dintre cele trei proiecte pe care le-am analizat folosesc o bibliotecă de teste unitare Catch2. Iar cea mai mare parte a mesajelor (!!! 90 din 138 într-unul și 297 din 344 în celălalt!!!) au următoarea formă:

Revizuire independentă a PVS-Studio (Linux, C++)

Nu ia în considerare multithreading

Există multe fals pozitive despre variabile presupuse neschimbate sau bucle nesfârșite, în timp ce lucrul cu aceste variabile are loc din fire diferite și, dacă nu ar fi așa, testele unitare nu ar funcționa.

Revizuire independentă a PVS-Studio (Linux, C++)

Cu toate acestea, poate un analizor static să țină cont de acest lucru? Nu stiu.

Rezultatele

PVS nu a găsit erori reale în proiectele mele open source Burst и Următorul, precum și într-un proiect de lucru, pe care, din motive evidente, nu îl pot prezenta. Adevărat, merită să rețineți că unele deficiențe au fost deja surprinse și corectate mai devreme folosind Cppcheck и scan-build.

În general, impresia de la toate aceste analizoare este aproximativ aceeași: da, prind ceva, uneori chiar ceva important, dar per total compilatorul este suficient.

Este posibil (și personal îmi place să cred așa) ca echipa noastră să folosească practici de dezvoltare de software care ne permit să generăm o cantitate minimă de cod de rahat. Este mai bine să nu creezi probleme decât să le depășești eroic.

Prin urmare, îmi asum libertatea de a da câteva sfaturi despre cum să scrieți în C++, astfel încât să nu împușc picioarele nimănui sau să nu loviți pe nimeni în frunte cu o greblă.

Profitați la maximum de diagnosticarea compilatorului

Echipa noastră utilizează (și vă sfătuiește să faceți acest lucru) următoarele opțiuni de compilare:

-Werror

-Wall
-Wextra
-Wpedantic

-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wenum-compare
-Wfloat-equal
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo

Activați-le în proiectul dvs. și aflați multe despre codul dvs.

Respectați standardul

Încercați să nu utilizați lucruri dependente de platformă dacă există analogi standard și, dacă absolut nu puteți face fără ele, înfășurați-le în blocuri speciale pentru macrocomenzi (sau altceva) și pur și simplu nu lăsați codul să fie compilat în condiții neacceptate.

Respectați semantica operațională standard

Adunarea trebuie să fie adunare, înmulțirea trebuie să fie înmulțire, apelul de funcție trebuie să fie apel de funcție, copia trebuie să fie copie, transportul trebuie să fie transportat, containerul trebuie să fie iterabil, iteratorul trebuie să aibă promovare ++ si dereferentiere *. Și așa mai departe și așa mai departe.

Cred că ideea este clară. Există convenții stabilite care nu sunt obligatorii, dar pe care toți utilizatorii și cititorii codului dvs. se așteaptă să le vadă. Nu încerca să-i depășești pe alții, altfel te vei depăși pe tine însuți.

Scrieți codul compatibil

În primul rând, mă refer la biblioteca standard. Este foarte de dorit ca interfețele claselor și funcțiilor dvs. să poată fi utilizate cu biblioteci standard și alte biblioteci (de exemplu, Boost).

Simțiți-vă liber să aruncați o privire la interfețele STL și Boost. Cu rare excepții, vei vedea acolo un model demn de urmat.

Profitați la maximum de instrumentele open source

Pentru aceeași analiză statică, există cel puțin două instrumente gratuite deschise care pot fi conectate o singură dată la orice proiect cu sistemul de construire CMake.

Puteți citi mai multe despre asta în publicația mea recentă.

postfață

În cele din urmă, aș dori să subliniez că nu susțin să nu se utilizeze PVS sau orice alte analizoare statice. Dar vă încurajez să vă gândiți cum sa întâmplat ca analizorul static să găsească în mod constant erori semnificative în codul dvs.

Aceasta este doar o consecință. Trebuie să căutăm și să eliminăm cauza.

Sursa: www.habr.com

Adauga un comentariu