Вебинар: Использование статических анализаторов кода при разработке безопасного ПО - 19.12
Одним из недостатков методологии статического анализа кода является наличие ложноположительных (false positives) предупреждений. Инструмент сигнализирует о возможных проблемах там, где их нет.
Разработчики инструментов статического анализа кода прикладывают много усилий, чтобы сократить количество ложных срабатываний. У кого-то это получается лучше, у кого-то хуже. Важно принимать, что проблема ложных срабатываний неразрешима на теоретическом уровне. Можно стремиться к идеалу, но никогда не получится создать анализатор, который совсем не ошибается.
Причиной является проблема останова: это теорема, которая доказывает, что невозможно разработать общий алгоритм, который бы по исходному коду программы определял, зациклится она или завершится за конечное время. Расширением данной теоремы является теорема Райса, утверждающая, что для любого нетривиального свойства вычислимых функций определение того, вычисляет ли произвольная программа функцию с таким свойством, является алгоритмически неразрешимой задачей.
Впрочем, даже если не вдаваться в теорию, легко продемонстрировать ситуацию, когда неочевидно, содержит код ошибку или нет. Для примера возьмём диагностику V501, реализованную в анализаторе PVS-Studio.
Идея диагностики очень простая. Подозрительно, когда совпадает левый и правый операнд у операторов ==, <, >, && и так далее. Пример:
if (A == A)
Почти всегда это опечатка. Это подтверждается большим количеством ошибок, найденных данной диагностикой в реальных открытых проектах. Казалось бы, такая простая и удачная диагностика не может давать ложные срабатывания. К сожалению, это не так. Реальный корректный код из одной математической библиотеки:
__host__ __device__ inline int isnan(float x){
return x != x;
}
Сравнивая переменную типа float саму с собой можно узнать, является её значение не числом (NaN) или нет.
NaN не равен ни одному другому значению (даже самому себе). Благодаря этому один из распространённых, однако неочевидных способов проверки результата на NaN — это сравнение полученной величины с самой собой.
Многие анализаторы выдадут на этот код предупреждение, хотя функция работает правильно. Конечно, для таких целей лучше использовать функцию std::isnan. Однако рассмотренный код корректен, и его аналоги встречаются в большом количестве приложений. Поэтому выдача предупреждений для сравнения двух одинаковых переменных в этом конкретном коде является ложным срабатыванием.
Анализатор PVS-Studio идёт дальше и пытается угадать, находится ли перед ним функция, выявляющая нечисла. Диагностика V501 промолчит, если сравниваются одинаковые переменные типа float и где-то рядом есть сочетание букв "NaN", "nan", "Not a Number" и т.д. То есть анализатор промолчит на показанный выше код.
К сожалению, хотя такие эмпирические исключения крайне полезны, они ненадёжны. Встретив где-то в тексте программы сравнение float переменной A == A и не имея дополнительных подсказок, анализатор будет вынужден выдать предупреждение. Однако, как мы теперь знаем, такой код может быть корректен, если программист хочет выявить наличие NaN. Да, такой код плох, так как путает не только анализатор, но и других программистов. Однако он может быть корректен и делать ровно то, что должен.
Таких неоднозначностей всегда много, и анализаторы кода балансируют между опасностью не сообщить о какой-то ошибке и опасностью выдать большое количество ложных срабатываний.
Большое количество ложных срабатываний плохо тем, что программист начинает пренебрежительно относиться к отчёту анализатора. И, встретив не очень понятное предупреждение, программист предрасположен сразу посчитать его ложным. Он не попытается разобраться подробнее. Это печально, так как часто анализаторы кода находят как раз неприметные ошибки в коде, который, на первый взгляд, выглядит хорошо. Примеры: 1, 2.
Чтобы компенсировать проблему ложных срабатываний, инструменты предлагают разнообразные вспомогательные механизмы, позволяющие настроить диагностики, подавить ложные предупреждения и отложить малозначимый технический долг на потом. См. также статью "Как внедрить статический анализатор кода в legacy проект и не демотивировать команду".
Если вы столкнулись с ложными срабатываниями PVS-Studio, для которых, как вы считаете, можно запрограммировать исключение в диагностике, предлагаем отправить нам соответствующую информацию и синтетический пример кода. Мы постараемся доработать анализатор.
Дополнительные ссылки:
0