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

Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
GBP
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;

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

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

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

Популярные статьи по теме
Зло живёт в функциях сравнения

Дата: 19 Май 2017

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

Возможно, читатели помнят мою статью под названием "Эффект последней строки". В ней идёт речь о замеченной мной закономерности: ошибка чаще всего допускается в последней строке однотипных блоков текс…
Статический анализ как часть процесса разработки Unreal Engine

Дата: 27 Июн 2017

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

Проект Unreal Engine развивается - добавляется новый код и изменятся уже написанный. Неизбежное следствие развития проекта - появление в коде новых ошибок, которые желательно выявлять как можно раньш…
Любите статический анализ кода!

Дата: 16 Окт 2017

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

Я в шоке от возможностей статического анализа кода, хотя сам участвую в разработке инструмента PVS-Studio. На днях я был искренне удивлён тому, что анализатор оказался умнее и внимательнее меня.
Характеристики анализатора PVS-Studio на примере EFL Core Libraries, 10-15% ложных срабатываний

Дата: 31 Июл 2017

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

После большой статьи про проверку операционной системы Tizen мне было задано много вопросов о проценте ложных срабатываний и о плотности ошибок (сколько ошибок PVS-Studio выявляет на 1000 строк кода)…
Эффект последней строки

Дата: 31 Май 2014

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

Я изучил множество ошибок, возникающих в результате копирования кода. И утверждаю, что чаще всего ошибки допускают в последнем фрагменте однотипного кода. Ранее я не встречал в книгах описания этого …
Как и почему статические анализаторы борются с ложными срабатываниями

Дата: 20 Мар 2017

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

В своей предыдущей статье я писал, что мне не нравится подход, при котором статические анализаторы кода оцениваются с помощью синтетических тестов. В статье приводился пример, воспринимаемый анализат…
PVS-Studio ROI

Дата: 30 Янв 2019

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

Время от времени нам задают вопрос, какую пользу в денежном эквиваленте получит компания от использования анализатора PVS-Studio. Мы решили оформить ответ в виде статьи и привести таблицы, которые по…
Главный вопрос программирования, рефакторинга и всего такого

Дата: 14 Апр 2016

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

Вы угадали, ответ - "42". Здесь приводится 42 рекомендации по программированию, которые помогут избежать множества ошибок, сэкономить время и нервы. Автором рекомендаций выступает Андрей Карпов - тех…
PVS-Studio для Java

Дата: 17 Янв 2019

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

В седьмой версии статического анализатора PVS-Studio мы добавили поддержку языка Java. Пришло время немного рассказать, как мы начинали делать поддержку языка Java, что у нас получилось и какие дальн…
Бесплатный PVS-Studio для тех, кто развивает открытые проекты

Дата: 22 Дек 2018

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

В канун празднования нового 2019 года команда PVS-Studio решила сделать приятный подарок всем контрибьюторам open-source проектов, хостящихся на GitHub, GitLab или Bitbucket. Им предоставляется возмо…

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

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