Институт системного программирования им. В.П. Иванникова РАН


SharpChecker. Инструмент статического анализа для поиска ошибок в исходном коде программ на языке С#

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

Область применения

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

В первую очередь, такой инструмент полезен для разработчиков. Существует несколько типовых сценариев использования статического анализатора. Регулярный анализ – наиболее эффективный подход. За счёт интеграции в CI разработчиков и технологиям сравнения и сортировки результатов анализа SharpChecker позволяет реализовать стратегию полного отсутствия новых предупреждений для каждого коммита в репозиторий проекта. Интеграция в Microsoft Visual Studio предоставляет возможность выполнять локальный анализ на машине разработчика, а интеграция в CI – анализ перед добавлением в систему контроля версий.

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

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

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

Таким образом, комбинация различных подсистем платформы SharpChecker позволяет комфортно использовать анализатор во всех сценариях применения статического анализатора и соответствует всем требованиям для инструмента промышленного качества.

Основные возможности SharpChecker

Исследования по технологиям статического анализа ведутся в ИСП РАН с 2002 года, поэтому инструмент SharpChecker использует самые современные научные подходы в области анализа программ. Это позволяет достигать высокой производительности и высокого качества результатов в сравнении с коммерческими аналогами, используемыми в промышленной разработке. В 2015 году SharpChecker как часть инструмента Svace внедрён в компании Samsung в качестве основного инструмента статического анализа, заменив общепризнанного мирового лидера в отрасли. Среди основных возможностей инструмента можно выделить:

  • хорошее качество результатов (60-100% истинных срабатываний);
  • высокая производительность (Roslyn 1.7 MLoС ~35min на Core i7 6700 4 ядра);
  • более 100 различных типов ошибок, поиск которых основан на трёх видах анализа: синтаксическом, анализе потоков данных, символьном выполнении, в т.ч. межпроцедурном;
  • понятные и подробные сообщения об ошибках, содержащие трассы, указывающие не только на место возникновения проблемы, но также причины и условия возникновения (путь в программе);
  • отображение ошибок с помощью централизованного сервера истории в браузере и непосредственно в среде разработки Microsoft Visual Studio;
  • поддержка ОС Windows XP, 7, 8, 10 32- и 64-битная (рекомендуется), Linux;
  • минимальная первичная настройка и учёт различных конфигураций анализируемого проекта за счёт перехвата сборки (msbuild, xbuild);
  • моделирование функций без исходного кода (более 40 тыс. моделей библиотечных функций реализовано).

Категории ошибок

SharpChecker способен обнаруживать более 100 различных типов ошибок, начиная от распространённых шаблонов синтаксических ошибок, заканчивая поиском утечек ресурсов, разыменования null. Одним из основополагающих принципов разработки анализатора является нацеленность на поиск ошибок, а не проверку на соответствие стандартам программирования или «лучшим практикам». По сравнению с формальной проверкой стандарта, это позволяет выдавать меньшее количество предупреждений, которые с более высокой вероятностью указывают на проблему в программе. Наиболее интересными являются следующие группы ошибок.

  1. Поиск утечек ресурсов.

    В контексте языка C# самым распространённым случаем является пропуск вызова Dispose для IDisposable объектов, что может привести к ошибке выполнения из-за преждевременного достижения предела памяти или других системных ресурсов, например, дескрипторов файлов. Поиск утечек ведётся по всем возможным путям выполнения с учётом возможных исключений.

  2. Поиск разыменования null.

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

    • разыменование переменной, которой было присвоено значение null (возможно неявно);
    • разыменование переменной, которой был присвоен результат функции, способной возвращать null (в том числе статистический анализ);
    • разыменование переменной после сравнения с null без проверки;
    • сравнение переменной с null после разыменования;
    • разыменование после оператора as без проверки.
  3. Неправильное использование блокировок, поиск недостающих синхронизаций, поиск взаимных блокировок, некорректное использование атрибута ThreadStatic.

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

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

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

  5. Проблемы приведения типов реализованы в нескольких группах предупреждений.

    Одни служат для обнаружения InvalidCastException во время выполнения, другие позволяют упростить или улучшить код.

  6. Ошибки, возникшие в результате копирования куска кода, при котором были внесены не все необходимые изменения.
  7. Ошибки, приводящие к проблемам с производительностью, например, результат вычисления функции не используется или конкатенация строк внутри цикла.
  8. Ошибки использования функций проекта и стандартной библиотеки.

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

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

Трассы ошибок

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

Моделирование функций

Для достижения качественных результатов анализа необходима информация о функциях без исходного кода - из стандартных или прикладных библиотек. Анализатор имеет механизм использования и интерфейс для создания моделей таких функций. Для наиболее распространённых библиотечных функций (более 40000) модели уже разработаны и входят в поставку.

Отображение ошибок

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

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

Функция централизованного обозревателя ошибок реализуется с помощью сервера истории анализа, который имеет веб-интерфейс и API для взаимодействия с подсистемами непрерывной интеграции пользователей. Кроме того, разработано расширение Microsoft Visual Studio, позволяющее выполнять анализ и исследовать результаты на машине разработчика.

Таким образом, разработанный в ИСП РАН на основе передовых научных подходов в области статического анализа инструмент SharpChecker полностью удовлетворяет требованиям анализатора промышленного качества и используется в индустрии.

SharpChecker

Разработчик/участник

Компиляторные технологии

Перейти к списку всех технологий