27 December 2011

Еще одно тестирование PVS-Studio

Designing and refactoring
Интерес к статическим анализаторам кода у меня уже давно, с первого знакомства с Klocwork где-то лет шесть назад. Кроме него, довелось некоторое время поработать с PCLint. И вот теперь немного потестировал PVS-Studio. (А на очереди – Parasoft и Coverity).

Тестирование я провел исключительно из любви к искусству – интересно было попробовать еще один анализатор.

PVS-Studio, похоже, ориентирован исключительно на работу с Visual Studio. После инсталляции он автоматически интегрируется в установленную версию студии. На этом все необходимые шаги по интеграции заканчиваются. Осталось запустить саму студию – и в ней уже будет новый пункт меню PVS-Studio. Столь прозрачная интеграция – выше всяких похвал!

Чтобы запустить анализатор, достаточно из этого меню выбрать, например, Check Solution. Процесс, надо сказать, небыстрый – на моем не очень большом проекте он занял 18 минут (для сравнения — полная сборка проекта длится около 2 минут). Из плюсов – анализатор показывает адекватный прогресс-бар и оставшееся время!

А вот то, что анализ кода автоматически добавится к сборке, меня слегка удивило. Особенно из-за того, что кроме как по маленькой иконке в трее, этого больше не было никак видно. На первый взгляд, ничего не происходит, сборка завершена, а в меню PVS-Studio почему-то все пункты меню стали серыми. Красивого окна с прогресс-баром видно почему-то не было.

Вывод результатов анализа – в отдельной вкладке PVS-Studio. Сделано все весьма удобно: по каждой найденной (потенциальной) проблеме показывается описание, место (файл и строка), а также ссылка на подробное описание проблем данного типа: почему это проблема, каким образом ее можно исправить и т.п. Описания сделаны очень подробно и качественно!

По двойному щелчку мышкой студия корректно перебросит вас в проблемное место. Правда, если проблема затрагивает более одного места, то второе придется находить вручную.

Также по каждой проблеме можно указать, что в данном случае произошло ложноположительное срабатывание, или вообще отключить отображение проблем данного класса.

Пункт меню “Incremental analysis after build”, на мой взгляд, делает не совсем то, что я бы ожидал. Если включить этот пункт, то анализ будет сделан только для изменившейся части проекта (единица изменения – файл, т.е. изменив в одном файле одну строку в одной функции, вы увидите все проблемы, найденные в этом файле). Я бы ожидал увидеть сравнение состояний между «было – стало», хотя может быть, вышеописанный режим работы тоже имеет смысл.

Похоже, что нет (по крайней мере, я не увидел) возможности увидеть результат очередного билда/исправления вроде «было 40 проблем, после исправления 6 проблем исчезло, 2 новые добавились». Без этого очень сложно отслеживать динамику проекта.

Сохранить отчет можно или во внутренний формат, или в plaintext. Сохранив его и открыв в текстовом редакторе, я вначале сильно удивился тому, что в отчете было гораздо больше проблем, чем показывалось в студии. Однако потом понял, в чем было дело – по умолчанию в студии включено отображение только “General analysis results”, а кроме этого есть еще и “64 bit analysis results”, выключенный по умолчанию, но попадающий в сохраненный отчет.

Что же, вернулся в студию и посмотрел еще и проблемы готовности к 64-м битам. Впечатлился. Однозначно могу рекомендовать тем, кто планирует переход на 64-битную платформу, анализатор находит множество неочевидных моментов, о которых даже не задумываешься, программируя в 32-битной системе, но которые приведут к проблеме при переходе на 64 бита. Например, «V104. Implicit type conversion to memsize type in an arithmetic expression» или «V102. Usage of non memsize type for pointer arithmetic», для вполне безобидного на первый взгляд кода:

    uint8 * pRecv;
    int cur = 0;
    
    // somewhere later...

    pRecv += cur;

Из непонравившегося – слишком тесная интеграция с Visual Studio. В документации настолько явно было написано, что работа с кроссплатформенными компиляторами очень сложна и не поддерживается, что даже не стал и пробовать, хотя хотелось бы. Теоретически есть возможность запустить PVS-Studio из командной строки, указав ему опции компилятора и список файлов, но – во первых, не так это и просто, если файлов много, и во-вторых, поддержка компилятора gnu в документации заявлена как отсутствующая, хотя возможно, что приложив некоторые усилия, удастся заставить анализатор что-то выдать и на проекте под кроссплатформенный компилятор.

И напоследок – краткое сравнение PVS-Studio с PC-Lint и Klocwork.

PVS-Studio гораздо более удобен в использовании, чем PC-Lint. Основная проблема PC-Lint – слишком большое количество потенциальных проблем, на этом же проекте с установками по умолчанию он выдает более 23 тысячи сообщений! (PVS-Studio – лишь 42). При этом PC-Lint не умеет скрывать повторяющиеся проблемы (если один и тот же .h файл подключается из двух .c файлов, то PC-Lint покажет проблему в .h файле дважды, а PVS-Studio – только один раз). И в PC-Lint нельзя отметить как false positive отдельно взятую проблему, можно только «выключить» весь класс проблем.

При этом если хорошо покопаться в горе «мусора», выдаваемой PC-Lint, то там можно найти больше реальных потенциальных проблем, чем находит PVS-Studio (который, например, не нашел отсутствие виртуальных деструкторов в паре классов, равно как и отсутствие явно определенных конструкторов копирования и конструкторов по умолчанию). Другое дело, что в PC-Lint эти полезные крупицы обычно «тонут» среди остальных, не столь критических сообщений.

При этом PC-Lint более универсален, хотя и гораздо более сложен в использовании, хотя интеграция в Visual Studio у него тоже достаточно простая.

Но в целом здесь PVS-Studio – безусловный лидер. Ибо с ней можно просто взять и начать работать, чего не скажешь о PC-Lint, где только на просмотр всех выданных сообщений легко может уйти пару дней!..

А вот по сравнению с Klocwork PVS-Studio, увы, проигрывает. Прежде всего по удобству использования (отмечу только отслеживание состояния от билда к билду – сколько проблем было исправлено, сколько осталось, а сколько добавилось, а также удобные отчеты), универсальности и лучшему нахождению критических потенциальных проблем. К тому же Klocwork – серверная многопользовательская система, с возможностью назначать ответственных за каждую найденную проблему и работать сразу с несколькими проектами, легко отслеживая статус каждого.

Если сравнить по ценам, то получится вот такой расклад (информация с сайтов разработчиков):
  • за PVS-Studio просят €3500 евро за 5 лицензий или €9000 за 30, за год использования.
  • за PC-Lint — $389 за одну лицензию или $3500 – за 10, неограниченно по времени.
  • за Klocwork — €30000 за пакет «сервер + 20 клиентов» за год использования.

Что же, цена примерно соответствует функциональности, PVS-Studio где-то посредине между дешевым, но тяжелым и неудобным в использовании PC-Lint и удобным и красивым, но дорогим Klocwork.

И напоследок – пару примеров реально найденных ошибок в проекте, над которым уже успели «поиздеваться» как Klocwork, так и PC-Lint, и который уже находится на стадии эксплуатации.

Кстати, скриншотов не привожу из-за того, что тестировал я все это на живом коммерческом проекте, а скриншоты содержат слишком много «закрытой» информации.

Например, PVS-Studio хорошо сообщает о проблемах вот такого типа (и этого не делают, насколько я заметил, вышеупомянутые анализаторы!):

V519. The 'x' variable is assigned values twice successively. Perhaps this is a mistake

В моем случае одна из таких выявленных проблем привела вот к такому коду:

    Year = Payload[1];
    Month = Payload[2];
    Year = Payload[3];

Который, конечно же, должен был выглядеть вот так:

    Year = Payload[1];
    Month = Payload[2];
    Day = Payload[3];

И это, кстати, на достаточно хорошо отлаженном, оттестированном и давно уже сданном в эксплуатацию продукте! Да и в целом все остальные выявленные подобные проблемы хоть и не были явными ошибками, но как минимум, указывали на, так сказать, не самый качественный, понятный и красивый код:

        txtL = _T("None");
        txtL = _T("Not found");

или

    POSITION pos = m_items.GetHeadPosition();
    pos = m_ownedItems.GetHeadPosition();

Также PVS-Studio хорошо обнаруживает подобные места в коде (хоть и не ошибка, но я бы предпочел, чтобы такого в коде не было):

    if (m_sc)
    {
        result = DoubleToString(m_highLimit,3);
    }
    else
    {
        result = DoubleToString(m_highLimit,3);
    }

сообщая про них, что: «The 'then' statement is equivalent to the 'else' statement»

Или вот такое (здесь m2 и m1 типа float):

    if ((m2 - m1) == 0.0)
    {
       doSomethingHere();
    }

говоря, что «An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(A — B) < Epsilon or fabs(A — B) > Epsilon»

В целом, если у вас в отделе около 30 разработчиков и вы пишете преимущественно в Visual Studio, а 30 тыс. евро на Klocwork у вас нет, то PVS-Studio – очень даже неплохой выбор!
Tags:pvs-studiostatic code analysis
Hubs: Designing and refactoring
+13
2.7k 13
Comments 24
Popular right now
Программист Power BI Senior
from 80,000 to 125,000 ₽ТатнефтьКазаньRemote job
BackEnd Engineering Lead - PHP/Golang - Dubai - relocation offered
from 8,000 to 9,000 $Tech Space LLCМосква
Hyperscale - Performance Engineer
from 150,000 to 350,000 ₽Rubrain.comRemote job
Rails programmer (Middle)
from 2,000 to 3,250 $UscreenRemote job
Squad lead (B2B) / Lead Developer
from 5,000 $WhiskRemote job
Top of the last 24 hours