Niezależna recenzja PVS-Studio (Linux, C++)

Zobaczyłem post o tym, że PVS nauczył się analizować w systemach Linux, i postanowiłem spróbować na swoich projektach. I oto, co z tego wynikło.


Spis treści

  1. Zalety
  2. Minusy
  3. Podsumowanie
  4. Epilog

Zalety

Responsywne wsparcie

Poprosiłem o klucz próbny, a tego samego dnia go otrzymałem.

Wystarczająco zrozumiała dokumentacja

Uruchomienie analizatora udało się bez większych problemów. Istnieje także pomoc dotycząca poleceń konsolowych (choć są pewne zastrzeżenia, patrz sekcja Minusy).

Możliwość analizy wielowątkowej

Analizator ma opcję "standardową" -j, która pozwala na równoległą analizę w kilku zadaniach. To znacznie oszczędza czas.

Dobra wizualizacja

Wiele różnych formatów wyjściowych, od tekstowego po niewielki interfejs webowy. Interfejs webowy jest wygodny, zwięzły, z podpowiedziami obok linii kodu i linkami do opisów diagnostyki.

Prosta integracja w budowę

Cała dokumentacja jest na ich stronie, powiem tylko, że jeśli Twój projekt jest budowany za pomocą CMake, to wszystko jest bardzo proste.

Dobre opisy diagnostyki

Jeśli generować wyjście w trybie fullhtml, to przy każdej wiadomości znajduje się link do opisu diagnostyki, z wyjaśnieniami, przykładami kodu i dodatkowymi linkami.

Minusy

Nieznajomość języka C++ przez analizator

Niestety, PVS czasami myli się w składni i generuje fałszywie pozytywne komunikaty dla całkowicie poprawnego kodu.

Na przykład, jest funkcja, która zwraca 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));
}

Tak, słowo kluczowe auto może oznaczać void, tak to już jest auto. Ale PVS zgłosił takie komunikaty:

dynamic_tuple_management.hpp:29:1: błąd: V591 Funkcja typu nie-void powinna zwrócić wartość.
dynamic_tuple_management.hpp:29:1: błąd: V2542 Funkcja o zwracanym typie nie-void powinna zwrócić wartość ze wszystkich ścieżek wyjścia.

Bardzo wolna strona

Tak, w interfejsie webowym obok każdej wiadomości jest link do odpowiedniego opisu diagnostyki z przykładami. Ale gdy klikniesz na link, trzeba dosyć długo czekać, a czasami zdarza się nawet 504 Gateway Time-out.

Język

Wszystkie opisy są w języku rosyjskim, co jest świetne. Ale linki z raportu zawsze prowadzą do wersji angielskiej. Dobrze by było mieć możliwość zmiany języka, aby przeglądać diagnostyki od razu po rosyjsku. W interfejsie nie znalazłem takiej opcji.

Niewygodnie pracować z poziomami diagnostyki przez konsolę

Zacznijmy od tego, że obie używane drużyny (to pvs-studio-analyzer i plog-converter) mają różne formaty zlecenia diagnostyki.

Pomoc do pvs-studio-analyzer głosi:

-a [TRYB], --analysis-mode [TRYB]
    TRYB definiuje typ ostrzeżeń:
    1 - błędy 64-bitowe;
    2 - zarezerwowane;
    4 - Analiza ogólna;
    8 - Mikrooptymalizacje;
    16 - Specyficzne żądania klientów;
    32 - MISRA.
    Tryby można łączyć przez dodawanie wartości.
    Domyślnie: 4

Długo próbowałem zrozumieć, gdzie należy dodawać („adding the values”) klucze. Próbowałem wymieniać je przecinkiem:

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

Próbowałem podawać klucz kilka razy:

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

I dopiero potem zrozumiałem, że to są maski bitowe! I trzeba suma, a nie dodawać wartości. Na przykład, aby uzyskać ogólne diagnozy, diagnozy mikrooptymalizacji i MISRA, trzeba je zsumować (4 + 8 + 32 = 44):

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

Używanie masek bitowych w interfejsach użytkownika to zazwyczaj zły ton. Można to było wszystko zsumować wewnętrznie, a użytkownikowi ustawić zestaw flag.

Ponadto, istnieje jeszcze narzędzie plog-converter, które generuje czytelną informację o analizie statycznej. Ma ono inne subtelności.

Pomoc do programu plog-converter informuje:

-a, --analyzer            Określa analizatory i poziomy, które będą
                          używane do filtrowania, tzn.
                          'GA:1,2;64:1;OP:1,2,3;CS:1;MISRA:1,2'
                          Domyślnie: GA:1,2

Pojawiły się tutaj jakieś „poziomy”, których wcześniej nigdzie nie było, a w dokumentacji też nic o nich nie znalazłem.

Ogólnie rzecz biorąc, nie jasne. Dlatego wszystko ustawiłem na maksimum.

Mnóstwo bezsensownego błagania w Catch

W dwóch z trzech projektów, które analizowałem, używana jest biblioteka testowania jednostkowego Catch2. I większość wiadomości (!!! 90 z 138 w jednym i 297 z 344 w drugim !!!) ma następujący wygląd:

Niezależna recenzja PVS-Studio (Linux, C++)

Nie uwzględnia wielowątkowości

Wiele fałszywych alarmów na temat rzekomych niezmiennych zmiennych lub nieskończonych pętli, podczas gdy praca z danymi tych zmiennych odbywa się z różnych wątków, a gdyby tak nie było, to testy jednostkowe by nie zadziałały.

Niezależna recenzja PVS-Studio (Linux, C++)

Zresztą, czy statyczny analizator może w ogóle coś takiego uwzględnić? Nie wiem.

Podsumowanie

PVS nie znalazł żadnego prawdziwego błędu w moich otwartych projektach Burst i Proxima, a także w projekcie roboczym, którego z oczywistych powodów nie mogę przedstawić. Warto jednak pamiętać, że niektóre niedociągnięcia zostały już wcześniej wychwycone i naprawione. Cppcheck i scan-build.

Ogólnie wrażenie ze wszystkich tych analizatorów jest w przybliżeniu takie samo: tak, coś łapią, czasami nawet coś ważnego, ale w całości wystarczy kompilator.

Może (i osobiście miło mi tak myśleć), że nasz zespół stosuje takie praktyki w rozwoju oprogramowania, które pozwalają generować minimalną ilość złej jakości kodu. Lepiej nie stwarzać problemów, niż heroicznie je przezwyciężać.

Dlatego pozwalam sobie dać kilka wskazówek dotyczących tego, jak pisać w języku C++, aby nikomu nie strzelać w nogi i nie dostawać w głowę od grabli.

Wykorzystuj diagnostykę kompilatora maksymalnie.

Nasz zespół wykorzystuje (i radzi wam) następujące opcje kompilacji:

-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

Zintegruj je w swoim projekcie, a dowiesz się wiele nowego o swoim kodzie.

Przestrzegaj standardu.

Staraj się nie używać rzeczy zależnych od platformy, jeśli istnieją standardowe odpowiedniki, a jeśli już całkowicie nie da się bez nich obejść, zapakuj je w specjalne bloki pod makrosy (lub w inny sposób) i po prostu nie pozwól skompilować swojego kodu w nieobsługiwanych warunkach.

Przestrzegaj standardowej semantyki operacji.

Dodawanie powinno być dodawaniem, mnożenie — mnożeniem, wywołanie funkcji — wywołaniem funkcji, kopiowanie powinno kopiować, przeniesienie — przenosić, kontener powinien być iterowalny, iterator powinien mieć pełzanie ++ i dereferencję. *. I tak dalej, i tak dalej.

Myślę, że myśl jest jasna. Istnieją ustalone konwencje, które nie są obowiązkowe, ale które wszyscy użytkownicy i czytelnicy twojego kodu oczekują zobaczyć. Nie próbuj przechytrzyć innych, bo sam się przechytrzysz.

Pisz kompatybilny kod.

Przede wszystkim mam na myśli standardową bibliotekę. Bardzo pożądane, aby interfejsy twoich klas i funkcji mogły być używane z bibliotekami standardowymi i innymi (np. Boost).

Nie krępuj się zaglądać do interfejsów STL i Boost. Z nielicznymi wyjątkami zobaczysz tam godny do naśladowania przykład.

Wykorzystuj maksymalnie otwarte narzędzia.

Istnieje co najmniej dwa otwarte, darmowe narzędzia do analizy statycznej, które można podłączyć do każdego projektu z systemem budowy CMake za pierwszym razem.

Więcej informacji można znaleźć w moim niedawnym artykule..

Epilog

Na koniec chciałbym podkreślić, że nie namawiam do zaprzestania korzystania z PVS ani innych analizatorów statycznych. Jednak zachęcam do zastanowienia się, jak to się stało, że analizator statyczny regularnie znajduje w twoim kodzie istotne błędy.

To tylko skutek. Należy szukać i eliminować przyczynę.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster