Что такое идеальный статический анализатор, или почему идеал не достижим




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

Характеристики идеального статического анализатора

Тех, кто не знаком с понятием статический анализ кода, я отсылаю по ссылке. Поэтому сразу назову характеристики идеала:

  • 100% обнаружение всех типов программных ошибок;
  • 0% ложных срабатываний;
  • высокая производительность - "вжи-и-и-и-к, и весь код проанализирован почти мгновенно";
  • интеграция с моей любимой (читай со всеми) IDE, работа под моей любимой (читай подо всеми) операционной системой, анализ кода на моем любимом (читай на любом) языке программирования;
  • free (freeware, open source);
  • качественная и быстрая поддержка.

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

100% обнаружение всех типов программных ошибок

Надо сразу же понимать, что ни один статический анализатор никогда не даст 100% обнаружение. Почему? Хотя бы потому, что некоторые классы ошибок лучше детектируются динамическими анализаторами. И конкурировать с ними в этом смысле глупо. Также как и динамические анализаторы не могут конкурировать со статическими по некоторым классам правил.

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

Ну и, наконец, статический анализатор не обладает знанием о том, что ДОЛЖНО быть в программе, не обладает искусственным интеллектом. Если в программе написано "A равно B", а должно быть "A не равно B", то статический анализ не очень поможет.

Поэтому единственный реальный вариант - это постоянно делать новые диагностические правила. Это никогда не даст 100% обнаружение ошибок, но будет постоянно приближать к нему.

0% ложных срабатываний

Любой статический анализатор имеет ложные срабатывания. Так как в конечном итоге только программист ЗНАЕТ, что ДОЛЖЕН делать этот код. Анализатор же видит, что ДЕЛАЕТ код и пытается ПОНЯТЬ, что ДОЛЖЕН делать код.

В предыдущем пункте про "100% диагностику всех ошибок" можно сделать наивное предположение: "А давайте детектить все, что движется и будет счастье!" В смысле обнаруживать все, что хоть сколько-нибудь похоже на ошибку. Но этот подход неправильный, так как количество ложных срабатываний будет зашкаливать. А есть мнение, что если пользователь видит 10 ложных срабатываний подряд, то он закрывает инструмент и не смотрит на него больше.

Для уменьшения количества ложных срабатываний есть следующие пути:

  • Постоянная работа с существующими правилами для уточнения их формулировок. Скажем, если раньше на тестовом проекте правило "срабатывало" 100 раз и 50 из них были ложные срабатывания, то после уточнения правила ложных срабатываний может остаться только 10. Правда, при этом можно потерять 1-2 удачных срабатывания, но тут уже постоянный вопрос компромисса.
  • Отказ от правил, которые уже не актуальны. Если только добавлять новые правила и никогда не удалять (не отключать) старые, то со временем ряд диагностик перестает быть актуальным.
  • Наличие удобных инструментов для работы с ложными срабатываниями. Например, в PVS-Studio есть механизм подавления ложных срабатываний. Отметив сообщение как ложное, в следующий раз вы его не увидите.

Высокая производительность

Все хотят, чтобы программа работала быстро, но быстро не всегда получается. Как правило, технология анализа кода требует больше ресурсов, нежели компилятор. Это происходит из-за того, что компилятор проверяет только уж совсем грубые ошибки, а анализатор может выполнить более тонкий анализ. Но для этого ему, естественно, необходимы дополнительные данные. И чем больше этих данных, тем глубже анализ и тем интереснее ошибки он может найти.

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

Менее очевидным является попытка анализировать не весь код единицы компиляции (файла), а лишь фрагмент кода. Это очень сложная задача и в общем виде ее решить чрезвычайно сложно (для любого языка). Ведь нужно найти и "вычислить" типы данные, проанализировать используемые классы и т.п. Затраты на "выделение" нужной для анализа части могут оказаться даже больше, чем если бы просто проанализировалось всё целиком.

Интеграция с моей любимой (читай со всеми) IDE, работа под моей любимой (читай подо всеми) операционной системой, анализ кода на моем любимом (читай на любом) языке программирования

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

Поддерживаемые (анализируемые) языки программирования

Программные ошибки, которые обнаруживают анализаторы кода, конечно же, могут проявляться в разных языках программирования и общие у этих ошибок есть. Везде люди забывают инициализировать переменные, путают кнопки при вводе программы и т.п. Однако разбор и анализ программы происходит ОЧЕНЬ сильно по-разному в зависимости от анализируемого языка программирования.

Если какой-то анализатор заявляет, что он поддерживает анализ программ на нескольких языках программирования, то, скорее всего, собственно модулей анализа в нем реализовано тоже несколько. Причем это может быть даже полностью скрыто от пользователя! Я пишу об этом лишь для того, чтобы люди понимали, что за фразой: "Ну что вам стоит сделать ТАКОЕ ЖЕ, но для C#/PHP/Java?", кроется очень много работы.

Поддерживаемые операционные системы

Очень наивно думать, что анализатор кода "всего лишь" работает с текстом и поэтому может работать на любой операционной системе. Конечно разные языки программирования по-разному "завязаны" на окружение. Кто-то больше, как C++, кто-то меньше, как PHP.

Откуда идет это различие? Дело в том, что для больших и мощных языков типа C++ существует несколько компиляторов, с их различиями и нюансами в синтаксисе языка. И код, который писался для компиляторов на Windows-платформе немножечко, но отличается от кода, который писался для компиляторов на Linux-платформе. Но хотя это отличие с точки зрения пользовательского кода не очень существенно, с точки зрения статического анализатора может оказаться важным. Потому что если в анализируемом коде встречаются ключевые слова, которые используются в этом конкретном компиляторе, то анализатор надо "обучить" им. В этом смысле поддержка еще одного компилятора или еще одной операционной системы, в общем-то, равнозначные задачи.

Повторюсь, что для более простых, чем C++, языков эта задача легче.

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

Поддерживаемые IDE

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

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

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

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

Free (freeware, open source) и качественная поддержка

Я объединил два пункта в один, так как они неразрывно связаны.

Инструменты статического анализа кода относятся к классу программ, для которых очень важна качественная и постоянная поддержка пользователей. Да, есть несколько инструментов, которые распространяются бесплатно, но до лидеров рынка (Coverity, Klocwork, Parasoft) они не дотянут скорее всего никогда.

Вообще же бесплатным и открытым инструмент статического анализа вполне может стать, если компанию-разработчика купит какой-нибудь гигант вроде Google, Microsoft или Intel, но это случай особенный.

Как правило, инструменты статического анализа продаются по модели подписки с ежегодным продлением. Это может, не нравится некоторым пользователям, но я постараюсь объяснить, почему такая схема лучше всего. И простите меня, что заглянув в пункт "Free" вы читаете про схемы лицензирования.

Как я уже сказал, для инструментов статического анализа очень важна поддержка. В статическом анализе поддержка означает, прежде всего, что анализатор может сначала не разобрать какой-то код (сложные шаблоны C++,нестандартные расширения компилятора и т.п.). И тогда важно оперативно (за несколько дней) доделать анализатор, чтобы код клиента обрабатывался. Еще в качестве поддержки надо клиентам нужна помощь в интеграции инструмента в их процесс разработки. Ну и реализация пожеланий клиентов, сильно упрощающая их жизнь тоже необходима.

Все это стоит денег. Поэтому продать лицензию один раз и затем всю жизнь бесплатно оказывать поддержку невозможно.

Можно было бы продавать новые major-релизы. Например, версии v3, v4, v5... Этот вариант плох тем, что он побуждает разработчика "придерживать" новые крутые возможности инструмента до следующей major-версии вместо того, чтобы выпустить их сразу, как только они оказались готовы.

Таким образом, получается, что ежегодное продление лицензии - самый оптимальный вариант. При этом какие-то компании-разработчики ставят цену продления как 100% от базовой цены, какие-то - меньше (дают скидку на продление). В случае со скидкой на продление это можно объяснить так, что первый год включает дополнительные затраты на обучение клиента работе с инструментом.

В результате получается, что качественный инструмент с качественной поддержкой free быть не может. Если только его не предлагает компания-гигант, но в этом случае об адресной поддержке конкретного клиента можно и не мечтать.

Заключение

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



Найдите ошибки в своем C, C++, C# и Java коде

Предлагаем попробовать проверить код вашего проекта с помощью анализатора кода PVS-Studio. Одна найденная в нём ошибка скажет вам о пользе методологии статического анализа кода больше, чем десяток статей.

goto PVS-Studio;


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

Проверено проектов
361
Собрано ошибок
13 417

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

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

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

goto PVS-Studio;