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


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

Динамический анализ может производиться для программ, написанных на различных языках программирования C, C++, Java, C#, PHP, Python, Erlang и многих других.

Для динамического анализа кода используются специальные утилиты, предназначенные для запуска программы, сбора и анализа полученных данных. Многие современные среды разработки уже содержат в своем составе инструменты для динамического анализа кода, например отладчик и профилировщик в Microsoft Visual Studio 2012.

Программы для динамического анализа различаются по способу взаимодействия с проверяемой программой:

  • инструментирование исходного кода - в исходный текст приложения, до начала компиляции, добавляется специальный код для обнаружения ошибок;
  • инструментирование объектного кода - код добавляется непосредственно в исполняемый файл;
  • инструментирование кода на этапе компиляции - проверочный код добавляется, используя специальные ключи компилятора (например, такой режим поддерживается компилятором GNU C/C++ 4.x);
  • не изменяет исходную программу, используются специализированные библиотеки этапа исполнения - для обнаружения ошибок используются специальные отладочные версии системных библиотек.

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

С помощью динамического тестирования могут быть получены следующие метрики:

  • используемые ресурсы - время выполнения программы в целом или ее отдельных модулей, количество внешних запросов (например, к базе данных), количество используемой оперативной памяти и других ресурсов;
  • цикломатическая сложность, степень покрытия кода тестами и другие метрики программы;
  • программные ошибки - деление на ноль, разыменование нулевого указателя, утечки памяти, "состояние гонки";
  • наличие в программе уязвимостей.

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

Тестирование может производиться по принципу белого или чёрного ящика. Их отличие только в том, что "белый ящик" — имеются данные о программном коде, а "черный ящик" - нет. Так же есть так называемый метод "серого ящика", когда известна структура программы, но в самом тестировании эти данные не используются.

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

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

Отдельной задачей, для которой могут использоваться сторонние утилиты - создание входных тестовых данных. Ряд утилит использует такую методику - помечает исходные данные и отслеживает их продвижение при выполнении программы. На следующей итерации запуска тестов утилитой будут сгенерирован новый набор входных параметров и так далее, до достижения требуемого результата.

Таким образом, динамический анализ имеет как слабые, так и сильные стороны.

Достоинства динамического анализа кода:

  • В большинстве реализаций появление ложных срабатываний исключено, так как обнаружение ошибки происходит в момент ее возникновения в программе; таким образом, обнаруженная ошибка является не предсказанием, сделанным на основе анализа модели программы, а констатацией факта ее возникновения;
  • зачастую не требуется исходный код; это позволяет протестировать программы с закрытым кодом.

Недостатки динамического анализа кода:

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

Имея свои сильные и слабые стороны, динамический анализ наиболее эффективно может быть использован вместе со статическим анализом кода.

Дополнительные материалы


Найденные ошибки

Проверено проектов
346
Собрано ошибок
13 188

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;