- PVSM.RU - https://www.pvsm.ru -

Пример, как в PVS-Studio появляются новые диагностики

Новая Си++ диагностика для PVS-Studio

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

Всё началось с проверки проекта COVID-19 CovidSim Model и статьи [1] про неинициализированную переменную. Проект оказался маленьким и написанным с использованием современного стандарта языка C++. Это значит, что он отлично может пополнить базу тестовых проектов для регрессионного тестирования ядра анализатора PVS-Studio.

Однако, прежде чем пополнить базу новым проектом, полезно просмотреть выдаваемые предупреждения, чтобы выявить новые закономерности (паттерны) ложных срабатываний и выписать их для дальнейшей доработки анализатора. Также это дополнительная возможность заметить, что ещё что-то не так. Например, сообщение неудачно описывает ошибку для определённой конструкции кода.

Программист, которому поручили добавить проект в тестовую базу, подошёл к задаче основательно и решил заглянуть в раздел MISRA-диагностик. Вообще, это делать было необязательно, так как это весьма специфичная группа диагностик, которую нет смысла включать для таких проектов, как CovidSim.

MISRA С и MISRA C++ диагностики предназначены для разработчиков встраиваемых систем, и их суть сводится к ограничению использования небезопасных конструкций программирования. Например, не рекомендуется применять оператор goto (V2502 [2]), так как он провоцирует создание сложного кода, в котором легко допустить логическую ошибку. Подробнее с философией стандарта кодирования MISRA можно познакомиться в статье "Что такое MISRA и как её готовить [3]".

Для прикладного программного обеспечения, которым как раз и является проект CovidSim, включать набор MISRA диагностик не имеет смысла. Пользователь просто утонет в огромном количестве малополезных для него сообщений. Например, экспериментируя с этим набором диагностик, мы получали более миллиона предупреждений для некоторых открытых проектов среднего размера. Грубо говоря, с точки зрения MISRA, в каждой третьей строчке кода может быть что-то не так :). Естественно, никто всё это смотреть и тем более править не будет. Проект или сразу разрабатывается с учётом MISRA рекомендаций, или для него этот стандарт кодирования неактуален.

Но мы отвлеклись от темы. Так вот, бегло просматривая MISRA предупреждения, коллега зацепился взглядом за предупреждение V2507 [4], выданное для этого фрагмента кода.

if (radiusSquared > StateT[tn].maxRad2) StateT[tn].maxRad2 = radiusSquared;
{
  SusceptibleToLatent(a->pcell);
  if (a->listpos < Cells[a->pcell].S)
  {
    UpdateCell(Cells[a->pcell].susceptible, a->listpos, Cells[a->pcell].S);
    a->listpos = Cells[a->pcell].S;
    Cells[a->pcell].latent[0] = ai;
  }
}
StateT[tn].cumI_keyworker[a->keyworker]++;

Правило V2507 заставляет оборачивать тела условных операторов в фигурные скобки.

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

Давайте присмотримся. Код только кажется корректным, но таковым не является! Фигурные скобки не относятся к оператору if.

Отформатируем код для наглядности:

if (radiusSquared > StateT[tn].maxRad2)
  StateT[tn].maxRad2 = radiusSquared;

{
  SusceptibleToLatent(a->pcell);
  ....
}

Согласитесь, это красивый баг. Он наверняка войдёт в Top10 C++ ошибок, найденных нами в 2021 году.

И что из этого следует? Подход, диктуемый стандартом MISRA, работает! Да, он заставляет писать везде фигурные скобки. Да, это утомительно. Но это оправданная плата за повышение надёжности встроенных приложений, используемых в медицинской технике, автомобилях и других системах высокой ответственности.

Хорошо, у разработчиков, использующих стандарт MISRA, всё нормально. Однако рекомендовать всем подряд использовать фигурные скобки – это плохая идея. Используя такой подход, очень легко довести анализатор до состояния, когда им станет невозможно пользоваться. Будет так много сообщений, что их просто никто не будет смотреть.

Вот мы и добрались для появления идеи для новой диагностики общего назначения. Можно сформулировать следующее правило.

Выдать предупреждение, если для оператора if выполняются следующие условия:

  • весь условный оператор if записан в одну строчку и имеет только then-ветку;
  • следующий statement после if – это compound statement, и он находится не на той же строке, что и if.

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

Именно так эта идея сейчас оформлена в нашей системе учёта задач. Возможно, в процессе реализации что-то будет сделано по-другому, но это уже неважно. Главное, появится хорошее диагностическое правило, которое начнёт выявлять новый паттерн ошибки. Далее мы распространим его на C# и Java ядра анализатора PVS-Studio.

Только что мы рассмотрели интересный пример, как было сформулировано новое диагностическое правило, которое затем будет реализовано в PVS-Studio. Скажем спасибо проекту CovidSim, стандарту кодирования MISRA и наблюдательности нашего коллеги.

Спасибо за внимание и следуйте за мной в мир С++ и багов :). Twitter [5]. Facebook [6].

Дополнительный ссылки:

  1. Технологии, используемые в анализаторе кода PVS-Studio для поиска ошибок и потенциальных уязвимостей [7].
  2. Под капотом PVS-Studio для Java: разработка диагностик [8].
  3. Использование машинного обучения в статическом анализе исходного кода программ [9].

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. Example of How New Diagnostics Appear in PVS-Studio [10].

Автор: Andrey Karpov

Источник [11]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie/362618

Ссылки в тексте:

[1] статьи: https://habr.com/ru/company/pvs-studio/blog/541036/

[2] V2502: https://www.viva64.com/ru/w/v2502/

[3] Что такое MISRA и как её готовить: https://habr.com/ru/company/pvs-studio/blog/482490/

[4] V2507: https://www.viva64.com/ru/w/v2507/

[5] Twitter: https://twitter.com/Code_Analysis

[6] Facebook: https://www.facebook.com/andrey.karpov.98/

[7] Технологии, используемые в анализаторе кода PVS-Studio для поиска ошибок и потенциальных уязвимостей: https://www.viva64.com/ru/b/0592/

[8] Под капотом PVS-Studio для Java: разработка диагностик: https://www.viva64.com/ru/b/0752/

[9] Использование машинного обучения в статическом анализе исходного кода программ: https://www.viva64.com/ru/b/0706/

[10] Example of How New Diagnostics Appear in PVS-Studio: https://habr.com/en/company/pvs-studio/blog/548080/

[11] Источник: https://habr.com/ru/post/548082/?utm_source=habrahabr&utm_medium=rss&utm_campaign=548082