Статический анализ программ
Стати́ческий ана́лиз програ́мм, вид анализа программ, который выполняется без запуска программы, в отличие от динамического анализа, происходящего при выполнении программы на некоторых конкретных входных данных. Устанавливаемые статическим анализом свойства, как правило, справедливы для всех входных данных или для некоторого значительного их подмножества. Кроме того, статический анализ подразумевает наличие автоматического или автоматизированного инструмента выполнения анализа (статического анализатора).
Первые алгоритмы анализа программ, использовавшиеся в ходе оптимизации программ в компиляторах классических императивных языков, были статическими. Позднее разработанные для компиляторов методы анализа оказались применимы и для других задач. В частности, одним из самых популярных применений статического анализа является поиск ошибок в программах. Однако статический анализ используется также для оптимизации программ после их компиляции (например, при оптимизации размера дистрибутива операционной системы), обратной инженерии программ, подсчёта метрик исходного кода, рефакторинга, понимания программ. Формальные методы математически строгого доказательства наличия у программы определённых свойств (формальная верификация) также могут рассматриваться как вид статического анализа.
Статический анализ программ чаще всего выполняется над исходным кодом программы или представлением, полученным из исходного кода, однако может выполняться и над объектным кодом. Теорема Райса гласит, что любое нетривиальное свойство программы не может быть точно установлено статическим анализом, поэтому, например, статические анализаторы, ищущие критические ошибки в исходном коде программ, могут выдавать предупреждения о несуществующих ошибках (ложноположительные срабатывания) или пропускать имеющиеся в действительности ошибки (ложноотрицательные срабатывания). При построении статических анализаторов стараются минимизировать либо ложноположительные, либо ложноотрицательные срабатывания, либо для заданного объёма программ добиться некоторого компромисса между ними.
Ошибки кодирования программ, подозрительные конструкции, ошибки, связанные с некорректными отступами в исходном коде программы и т. п., обычно ищутся с помощью анализа абстрактного синтаксического дерева каждой процедуры программы по отдельности. Примерами таких ошибок являются использование операции «=» (присваивание) вместо «==» (сравнение) в языке C, применение оператора sizeof к указателю вместо указываемого объекта и др. Анализ обычно заключается в поиске в синтаксическом дереве поддеревьев определённого вида, после чего в найденных поддеревьях проверяется корректность использования вершин. Такой анализ редко допускает ложноположительные срабатывания. Статический анализ, ищущий более сложные критические ошибки работы с памятью, многопоточные ошибки, неинициализированные переменные и пр., выполняется на представлении среднего уровня, как правило, для всей программы целиком. Примерами часто применяемых методов такого статического анализа являются анализ потока данных, абстрактная интерпретация, символьное выполнение.
Помимо классических методов статического анализа, базирующихся на теории компиляции, в последнее время развиваются методы на основе машинного обучения, в которых путём анализа значительного объёма кода пытаются вывести знание о том, как выглядят правильный и ошибочный коды. Такие методы пригодны для поиска ошибок алгоритмического характера (например, неверно выбрана одна переменная вместо другой), однако по точности поиска критических ошибок они пока отстают от классических методов. Кроме того, на основе машинного обучения развиваются методы автоматического исправления найденных ошибок, рефакторинга кода, генерации комментариев для рецензирования кода и т. п.