В теорії компіляторів, ме́ртвим ко́дом (англ. dead code, так само відме́рлим ко́дом, ма́рним ко́дом, неви́користаним ко́дом) називають код, який може бути виконаним (в чинній на поточний момент версії кодової бази), виконувався або міг бути виконаним раніше (до внесення в код на якомусь із моментів його існування змін, які зробили його марним), але результати його обчислень не впливають на подальшу роботу програми (зокрема, не використовуються)[1][2][3]. Іншими словами це код, що визначає тільки мертві змінні[en] або взагалі не визначає ніяких змінних.
Коли йдеться про початковий код, часто використовують загальніше поняття мертвого (відмерлого) коду, яке, крім марного коду, включає також недосяжний код[4][5].
Наявність у програмі мертвого коду збільшує її обсяг, тиск на ресурси (пристрої, регістри), тепловиділення і може збільшити час виконання, не несучи при цьому ніякої користі. В оптимізувальних компіляторах для виявлення і видалення мертвого і недосяжного кодів на рівні проміжного подання[en] використовують оптимізації видалення мертвого коду і видалення недосяжного коду. Для пошуку мертвого коду в сирцевому коді застосовують усілякі аналізатори і детектори мертвого коду[4][5]. Такі аналізатори, часто вбудовані в компілятор або IDE, виводять під час компіляції програми попередження про наявність у ній мертвого коду[6][7][8].
Приклади
Розглянемо такий приклад мовою Сі:
int foo(int x, int y)
{
int z; /* Оголошення мертвої змінної */
z = x/y; /* Мертвий код */
return x*y;
}
Тут операція z = x/y
є мертвим (марним) кодом, оскільки результат роботи цієї операції, змінна z
, надалі в програмі не використовується. Сама змінна z
є мертвою в процедурі foo
. Якщо змінна y
дорівнює нулю, то операція, яка виконує марне обчислення, спровокує виняток, отже її видалення, можливо, здатне змінити вивід програми. Оптимізація видалення мертвого коду видалить операцію z = x/y
, тільки якщо не буде сумнівів у тому, що через це не зміниться результат роботи програми[9].
Стосовно до початкового коду, недосяжний код часто називають мертвим, хоча, з точки зору теорії компіляторів, це різні речі. Розглянемо такий приклад:
int foo(void)
{
int x = 25;
return x;
x = 2*x; /* Недосяжний код */
return 0; /* Недосяжний код */
}
Тут, операції x = 2*x
і return 0
не будуть виконані за жодних умов, оскільки вони записані після безумовного повернення з процедури і є недосяжними (операції, що стоять після повернення з процедури можуть і не бути недосяжним кодом, наприклад, якщо на мітку, що стоїть після повернення посилається оператор goto). Оптимізація видалення недосяжного коду може видалити ці операції.
Аналіз
Для виявлення і видалення непотрібного коду, оптимізація видалення мертвого коду використовує результати аналізу потоку даних[en] (наприклад аналізу активних змінних[en]) або самостійно аналізує SSA-подання програми. Оптимізація видалення недосяжного коду аналізує граф потоку керування і усуває недосяжні вузли.
При роботі з марним кодом використовують консервативний підхід: якщо операція, що виконує марну дію, може провокувати виняток, і існує ненульова ймовірність того, що цей виняток впливає на вивід програми, то цієї операції видаляти не потрібно[9].
У сирцевому коді великих застосунків буває складно розпізнати мертвий код (марний і недосяжний). Для цього можуть застосовуватися детектори мертвого коду[4][5], що виконують статичний аналіз коду. Багато компіляторів і ІСР видають попередження про оголошені, але невикористовувані функції, методи, класи, змінні[6][7][8].
Мертвий код та інформаційна безпека
Для приховування алгоритмів, використовуваних у програмі, з метою захисту інтелектуальної власності, мертвий код може додаватися в програму навмисно, як затінювальне перетворення. Таке перетворення покликане збільшити ентропію коду, щоб ускладнити відновлення алгоритму, реалізованого в програмі. Так само, з метою затінення, в програму може додаватися недосяжний некоректний код: під час роботи програми така ділянка коду ніколи не виконується і не викликає помилок, але дизассемблер або декомпілятор під час роботи з цією ділянкою коду можуть повестися непередбачувано[10][11].
Наявність у програмі мертвого і недосяжного кодів може бути уразливістю, оскільки в такі ділянки коду можуть впроваджуватися програмні закладки[12][13].
Див. також
Примітки
- ↑ Engineering a Compiler — С. 544.
- ↑ Компиляторы — принципы, технологии, инструменты — С. 713, 714.
- ↑ Debray, S. K., Evans, W., Muth, R., and De Sutter, B. 2000. Compiler techniques for code compaction [Архівовано 22 травня 2003 у Wayback Machine.]. ACM Trans. Program. Lang. Syst. 22, 2 (Mar. 2000), 378—415. (summary)
- ↑ а б в Dead code detection and removal. Aivosto. Архів оригіналу за 5 серпня 2012. Процитовано 12 липня 2012.
- ↑ а б в Compares some free alternatives to DCD (Dead Code Detector). Java.net. Архів оригіналу за 23 вересня 2012. Процитовано 12 липня 2012.
- ↑ а б GCC online documentation. Options to Request or Suppress Warnings. GNU Compiler Collection. Архів оригіналу за 25 червня 2012. Процитовано 12 липня 2012.
- ↑ а б JDT Plug-in Developer Guide. Compiling Java code. eclipse.org. Архів оригіналу за 25 червня 2012. Процитовано 22 жовтня 2018.
- ↑ а б Discover dead code in your application using Code Analysis. Habib Heydarian, Microsoft Corp. Архів оригіналу за 23 вересня 2012. Процитовано 12 липня 2012.
- ↑ а б Appel, A. W. Modern Compiler Implementation in Java. — Cambridge University Press, 2004. — С. 360. — ISBN 0-511-04286-8.
- ↑ И. Ю. Иванов / Київський національний університет імені Тараса Шевченка / О проблемах защиты интеллектуальной собственности в программных системах // Проблеми прграмування. — 2006. — № 2-3 Спеціальний випуск — С. 68-72. (текст [Архівовано 2014-01-16 у Wayback Machine.])
- ↑ Обфускация и её преодоление // Лаборатория взлома. — Май 2006. — С. 8-13. (текст)
- ↑ Торшенко Ю. А. / СПб ГУ ИТМО / Модель и метод обнаружения уязвимостей на начальных этапах промышленного проектирования программного продукта. — 2008. (текст)
- ↑ Сакулина М. С. / Выявление и устранение «мертвого кода» с использованием технологии программирования IBM Rational Application Developer. (текст Архивировано)
Література
- Cooper and Torczon. Engineering a Compiler. — Morgan Kaufmann, 2011. — С. 544—550, 593. — ISBN 978-0-12-088478-0.
- Ахо, Альфред В.; Сети, Рави; Ульман, Джеффри Д. Компиляторы — принципы, технологии, инструменты. — Вильямс, 2003. — С. 713, 714, 733, 734. — ISBN 5-8459-0189-8.
- Muchnick, Steven S. Advanced Compiler Design and Implementation. — Morgan Kaufmann Publishers, 1997. — С. 592—597. — ISBN 1-55860-320-4.