Мёртвый язык
- 1 year ago
- 0
- 0
В теории компиляторов , мёртвым кодом ( англ. dead code , также отмершим кодом , бесполезным кодом, неиспользуемым кодом ) называют код, который может быть исполнен (в существующей на текущий момент версии кодовой базы), исполнялся или мог быть исполнен ранее (до внесения в код на каком-то из моментов его существования изменений, сделавших его бесполезным), но результаты его вычислений не влияют на дальнейшую программу (в частности, не используются) . Другими словами, это код, определяющий только или вообще не определяющий никакие переменные.
При рассмотрении исходного кода , часто используют другое, более общее понятие мёртвого (отмершего) кода , которое, кроме бесполезного кода , включает в себя недостижимый код .
Наличие мёртвого кода в программе увеличивает её размер, давление на ресурсы (устройства, регистры), тепловыделение и может увеличить время исполнения, не неся при этом никакой пользы. В оптимизирующих компиляторах для выявления и удаления мёртвого и недостижимого кодов на уровне промежуточного представления используются оптимизации удаления мёртвого кода и удаления недостижимого кода . Для поиска мёртвого кода в исходном коде применяются всевозможные анализаторы и детекторы мёртвого кода . Такие анализаторы часто бывают встроены в компилятор или IDE и выдают соответствующие предупреждения о наличии в программе мёртвого кода во время её компиляции .
Рассмотрим следующий пример на языке Си :
int foo(int x, int y)
{
int z; /* Объявление мёртвой переменной */
z = x/y; /* Мёртвый код */
return x*y;
}
Здесь, операция
z = x/y
является мёртвым (бесполезным) кодом, так как результат работы этой операции, переменная
z
, в дальнейшем в программе не используется. Сама переменная
z
является мёртвой в процедуре
foo
. Если переменная
y
равна нулю, то операция, выполняющая бесполезное вычисление, спровоцирует
исключение
, следовательно её удаление, возможно, способно изменить
вывод
программы. Оптимизация
удаления мёртвого кода
удалит операцию
z = x/y
, только если не будет сомнений в том, что из-за этого не изменится результат работы программы
.
Применительно к исходному коду , недостижимый код часто называют мёртвым, хотя с точки зрения теории компиляторов это разные вещи. Рассмотрим следующий пример:
int foo(void)
{
int x = 25;
return x;
x = 2*x; /* Недостижимый код */
return 0; /* Недостижимый код */
}
Здесь, операции
x = 2*x
и
return 0
не могут быть исполнены ни при каких условиях, так как они происходят после безусловного возврата из процедуры и являются недостижимыми (операции, стоящие после возврата из процедуры могут и не являться недостижимым кодом, например, если на метку, стоящую после возврата ссылается оператор
goto
). Оптимизация
удаления недостижимого кода
может удалить эту операцию.
Для выявления и удаления бесполезного кода, оптимизация удаления мёртвого кода использует результаты (например ) или осуществляет самостоятельный анализ SSA-представления программы. Оптимизация удаления недостижимого кода анализирует граф потока управления и устраняет недостижимые узлы.
При работе с бесполезным кодом используют консервативный подход: если операция, выполняющая бесполезное действие, может провоцировать исключение , и существует ненулевая вероятность того, что это исключение влияет на вывод программы, то не нужно удалять эту операцию .
В исходном коде больших приложений бывает сложно распознать мёртвый код (бесполезный и недостижимый). Для этого могут применяется детекторы мёртвого кода , выполняющие статический анализ кода . Многие компиляторы и IDE выдают предупреждения об объявленных, но неиспользуемых функциях, методах, классах, переменных .
Для сокрытия алгоритмов, используемых в программе, с целью защиты интеллектуальной собственности, мёртвый код может добавляется в программу намеренно, в качестве затеняющего преобразования . Такое преобразование призвано увеличить энтропию кода, чтобы затруднить восстановление алгоритма, реализованного в программе. Так же, в целях затенения, в программу может добавляться недостижимый некорректный код: во время работы программы такой участок кода никогда не исполняется и не вызывает ошибок, но дизассемблер или декомпилятор во время работы с этим участком кода могут повести себя непредсказуемо .
Наличие в программе мёртвого и недостижимого кодов может являться уязвимостью , так как в такие участки кода могут внедряться программные закладки .