Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

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

Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
Статический и динамический анализ кода

Статический и динамический анализ кода

13 Апр 2014

Мне, как разработчику инструмента статического анализа PVS-Studio, часто приходят предложения, реализовать в инструменте новую диагностику. Многие из предложений, опираются на опыт использования динамических анализаторов кода, например, Valgrind. К сожалению, часто это невозможно или почти невозможно. В этой статье я хочу кратко объяснить, почему статические анализаторы кода не могут делать то же самое, что динамические анализаторы и наоборот. Каждый из них силён в своё области. Один вид анализа не способен заменить другой, зато они отлично дополняют друг друга.

Статический анализ кода - это процесс выявления ошибок и недочетов в исходном коде программ. Статический анализ можно рассматривать как автоматизированный процесс обзора кода (code review).

Динамический анализ кода - это способ анализа программы непосредственно при ее выполнении.

Я часто слышу приблизительно следующую мысль:

У вас отличный инструмент. Но он не находит некоторые ошибки. Например, недавно Valgrind нашёл вот такую ошибку, а анализатор кода PVS-Studio промолчал. Было бы замечательно, добавить в PVS-Studio диагностику вот таких и таких ошибок. Тогда станет возможным использовать только один инструмент, что будет удобнее.

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

Предположим, что есть функция вида:

void OutstandingIssue(const char *strCount)
{
  unsigned nCount;
  sscanf_s(strCount, "%u", &nCount);
  
  int array[10];
  memset(array, 0, nCount * sizeof(int));
}

Статическому анализатору кода очень сложно понять, может произойти здесь выход за границу массива или нет. Если строка, которая конвертируется в число, читается из файла, то это вообще невозможно.

Чтение строки из файла, это крайний случай. Облегчим задачу. Предположим, что строка формируется где-то в другой функции. Тогда, теоретически анализ возможен. На практике же это нереально сложно. Нужно понять, в какой последовательности будет выполняться код, понять какие значения могут принимать переменные, что будет записано в буферы в памяти, возможен ли вариант, когда возникнет переполнение.

Хранение данных в строке приведено, чтобы продемонстрировать, как не просто работать статическому анализатору. И таких сложностей при анализе возникает масса. Чем дальше от места вычисления какого-то значения происходит его использование, тем сложней анализ. Если место формирования строки отделено от её использования вызовами нескольких функций, то я не представляю насколько сложен должен быть анализатор и сколько памяти ему потребуется. Количество возможных ветвлений и значений переменных растёт невообразимо быстро. Чтобы найти такую ошибку придётся практически виртуально выполнить программу, причём во всех возможных вариантах ветвления. Нереально сложная алгоритмическая задача, которая в добавок потребует недостижимых вычислительных ресурсов.

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

Более того, динамический анализатор решит задачу выхода за границу массива, даже если строка прочитана из файла!

Означает ли это, что динамический анализ лучше? Быть может стоит лучше усовершенствовать динамический анализатор, чтобы он умел тоже самое, что и статический?

И вновь ответ: к сожалению, ничего не получится. Есть задачи, с которыми легко справляется статический анализ и которые неразрешимы при динамическом анализе.

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

Для динамического анализатора в приведённом ниже коде нет никаких проблем. Сравнивается часть буфера. Ничего подозрительного. Полным полно ситуаций, когда функция memcmp() сравнивает не весь выделенный буфер памяти, а только его часть. Это очень частое явление, когда используется только часть буфера. Ругаться динамическому анализатору здесь не на что.

А вот статический анализатор смотрит на код и понимает, что количество сравниваемых байт, скорее всего вычисляется неверно. Пример, взятый из реального open source проекта:

const unsigned char stopSgn[2] = {0x04, 0x66};
....
if (memcmp(stopSgn, answer, sizeof(stopSgn) != 0))
  return ERR_UNRECOGNIZED_ANSWER;

Ошибка в том, что не там поставлена скобка. Статический анализатор легко замечает аномалию в коде и сообщает об этом. Для динамического анализатора здесь всё корректно. Сравнивается один байт. Бывает. Сравнение только одного байта частая ситуация, особенно в коде, построенного на макросах.

Заключение. Мы рассмотрели два примера ошибок. Каждый из анализаторов способен обнаружить только одну из них в силу тех принципов, которые положены в основу их работы. Как бы не хотелось, обойтись только одним инструментом, это невозможно. Наилучший результат можно получить только применяя статический и динамический анализ совместно.

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

Популярные статьи по теме
Дизайн и эволюция constexpr в C++

Дата: 13 Янв 2022

Автор: Гость

constexpr - одно из самых магических ключевых слов в современном C++. Оно дает возможность создать код, который будет выполнен еще до окончания процесса компиляции, что является абсолютным пределом д…
В чём проблемы первого отчёта статического анализатора и как их исправить?

Дата: 09 Дек 2021

Автор: Николай Миронов

Основная цель статического анализатора – найти и показать ошибки в коде, чтобы вы могли их исправить. Однако показать ошибки — это не так просто, как кажется на первый взгляд. Есть ряд проблем, с кот…
C++20 Ranges — Полное руководство

Дата: 07 Дек 2021

Автор: Гость

C++20 Ranges, также известные как STL v2, эффективно заменяют существующие возможности и алгоритмы STL. В этой статье я расскажу вам о нововведениях, которые внесли собой Ranges. Также мы поговорим о…
Вызов виртуальных функций в конструкторах и деструкторах (C++)

Дата: 26 Ноя 2021

Автор: Андрей Карпов

В разных языках программирования поведение виртуальных функций отличается, когда речь заходит о конструкторах и деструкторах. Неправильное использование виртуальных функций – это классическая ошибка …
Обзор нововведений в C# 10

Дата: 20 Окт 2021

Автор: Валентин Прокофьев

В данной статье мы рассмотрим новую версию языка C# 10, которая включает в себя небольшой список изменений относительно C# 9. Ниже приведены их описания вместе с поясняющими фрагментами кода. Давайте…

Комментарии (0)

Следующие комментарии
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять