Пример Использования Статического Анализатора

Когда PVS-Studio объявила, что наконец-то выпустила самостоятельную версию, не требующую для работы Visual Studio, я, конечно, не мог это проигнорировать :) До этого я уже поигрался с пробной версией, используя код одного из старые проекты.

Теперь у нас есть возможность взглянуть на код нашего последнего проекта, который собирается в среде разработки AVR Studio (основанной на eclipse).

Для работы нужны файлы сразу после препроцессора.

Среда AVR Studio может это сделать, за одним небольшим исключением — после включения флага «Только препроцессор» выходные данные фактически содержат файлы после препроцессора — но все равно с расширением .

o вместо ожидаемого .

i. Что ж, 5-минутный Python-скрипт решает это недоразумение, и анализатор прекрасно запускается! На удивление сообщений мало – около двух десятков.

Большинство из них — это незначительные комментарии или ложные срабатывания (во встроенных случаях происходит запись одного и того же значения в регистр дважды подряд, но анализатор видит в этом потенциальную проблему (и я в целом с этим согласен — лучше перестраховаться и проверить такие места)).

В паре мест настоящие опечатки и ошибки копипаста.

Например, переменная типа одного перечисления сравнивается со значением из другого перечисления.

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

Но самое интересное, ради чего я и пишу этот пост, — это одна-единственная строчка «Возможное разыменование NULL-указателя»… Так получилось, что по всему коду такая конструкция типа

  
  
  
   

void fun(error_t * perr) { *perr = SUCCESS; .

if (something) { *perr = SOME_ERROR; } }

И буквально в нескольких функциях дизайн немного отличался:

void init(void) { error_t err = SUCCESS; .

fun(&err); }

Пока однажды после одного из небольших рефакторингов в одном из мест не появилось следующее:

void some_init(void) { error_t *perr = SUCCESS; .

some_fun(perr); }

Собственно, анализатор выругался на этой строчке.

УСПЕХ, конечно, имел значение 0. Давайте отмотаем время немного назад, к тому моменту, когда это изменение попало в репозиторий.

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

Проверка кода оставила эту строку незамеченной (слишком часто в коде появлялись строки *perr = SUCCESS).

Примерно через 30 дней после того самого коммита ночные тесты впервые провалились.

Воспроизвести падение не удалось.

Затем испытания снова провалились.

И далее.

Экспериментально было установлено, что сбой происходит в среднем один раз на каждые тридцать запусков набора тестов.

На поиск ошибки команда потратила около 50 часов.

Безуспешно.

Правда, нам удалось локализовать коммит, после которого все началось — но причину так и не нашли.

Причина, кстати, была на две ступени ниже.

Функция some_fun(perr) внутренне называется some_other_fun(perr), и эта функция называется some_ Third_fun(perr).

И уже в some_ Third_fun(perr) был код, проверявший, произошла ли ошибка:

for(number_of_loops) { some_action(perr); if (*perr != SUCCESS) return; }

Те.

несмотря на то, что в функции some_action ошибок не возникло (что было очень нетривиально, с участием кучи внешней периферии - именно поэтому локализация проблемы оказалась не самой простой задачей), продолжение цикла зависело от записанного в нее значения адрес 0 (в большинстве случаев встроенный нулевой адрес совершенно законен).

И в подавляющем большинстве случаев на этот адрес записывалось 0. Резюме: ошибка, на поиск которой безуспешно ушло около 50 часов, была обнаружена и исправлена менее чем за час с помощью одного запуска анализатора! Веская причина использовать анализатор? Увы, не всегда.

В частности, у нас точно такой же случай: проект с оплатой по временной и материальной схеме.

Поскольку 50 часов, потраченные на поиск, оплачиваются заказчиком, для руководства внедрение анализатора означает прямые потери:((( И кстати: в проекте используется FreeRTOS. Итак, в ее коде не было ни одного предупреждения! И да, этот пост чисто из любви к искусству анализаторов.

Теги: #статический анализ кода #pvs-studio #C++ #программирование #Идеальный код #C++

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.