stringtranslate.com

Недоступный код

В компьютерном программировании недостижимый код — это часть исходного кода программы, которая никогда не может быть выполнена, поскольку не существует пути управления потоком выполнения к коду из остальной части программы. [1]

Недостижимый код иногда также называют мертвым кодом , [2] [3] хотя мертвый код может также относиться к коду, который выполняется, но не оказывает никакого влияния на вывод программы. [4]

Недостижимый код обычно считается нежелательным по нескольким причинам:

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

Причины

Недоступный код может существовать по многим причинам, например:

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

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

Примеры

В этом фрагменте кода на языке C:

int foo ( int X , int Y ) { return X + Y ; int Z = X * Y ; }               

определение int Z = X * Y; никогда не достигается, так как функция всегда возвращается до него. Поэтому Z не нужно ни выделять память, ни инициализировать.

ошибка goto fail

В SSL/TLS от Apple с февраля 2014 года содержалась серьезная уязвимость безопасности, официально известная как CVE - 2014-1266 и неофициально как «ошибка goto fail». [5] [6] Соответствующий фрагмент кода [7] выглядит следующим образом:

static OSStatus SSLVerifySignedServerKeyExchange ( SSLContext * ctx , bool isRsa , SSLBuffer signedParams , uint8_t * signature , UInt16 signatureLen ) { OSStatus err ; ... if (( err = SSLHashSHA1.update ( & hashCtx , & serverRandom )) ! = 0 ) перейти к сбою ; if (( err = SSLHashSHA1.update ( & hashCtx , & signedParams )) != 0 ) перейти к сбою ; перейти к сбою ; if ( ( err = SSLHashSHA1.final ( & hashCtx , & hashOut )) != 0 ) перейти к сбою ; ... сбой : SSLFreeBuffer ( & signedHashes ) ; SSLFreeBuffer ( & hashCtx ); возврат ошибки ; }                                                 

Здесь есть два последовательных goto failоператора. В синтаксисе языка C второй является безусловным, и поэтому всегда пропускает вызов SSLHashSHA1.final. Как следствие, errбудет удерживать статус операции обновления SHA1, и проверка подписи никогда не будет неудачной. [5]

Здесь недостижимый код — это вызов функции final. [6] Применение компилятора Clang с опцией -Weverythingвключает анализ недостижимого кода, который вызовет сигнал тревоги для этого кода. [6]

С++

В C++ некоторые конструкции определены как имеющие неопределенное поведение . Компилятор может реализовать любое поведение или не реализовать никакого, и обычно оптимизирующий компилятор предполагает, что код недостижим. [8]

Анализ

Обнаружение недостижимого кода — это форма анализа потока управления для поиска кода, который никогда не может быть достигнут ни в одном возможном состоянии программы. В некоторых языках (например, Java [9] ) некоторые формы недостижимого кода явно запрещены. Оптимизация, которая удаляет недостижимый код, известна как устранение мертвого кода .

Код может стать недоступным в результате преобразований, выполняемых оптимизирующим компилятором (например, исключение общих подвыражений ).

На практике сложность анализа оказывает значительное влияние на количество обнаруженного недостижимого кода. Например, сворачивание констант и простой анализ потока показывают, что внутренняя часть оператора if в следующем коде недостижима:

целое N = 2 + 1 ;     если ( N == 4 ) { /* недостижимо */ }    

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

двойной X = sqrt ( 2 );   если ( X > 5 ) { /* недостижимо */ }    

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

Недоступность против профилирования

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

Смотрите также

Ссылки

  1. ^ Debray, Saumya K.; Evans, William; Muth, Robert; De Sutter, Bjorn (1 марта 2000 г.). «Методы компиляции для уплотнения кода». ACM Transactions on Programming Languages ​​and Systems . 22 (2): 378–415. CiteSeerX 10.1.1.43.7215 . doi :10.1145/349214.349233. S2CID  6129772. 
  2. ^ RTCA/DO-178C Software Considerations in Airborne Systems and Equipment Certification. RTCA, Inc. 2011. стр. 112. Получено 11 июня 2019 г. Мертвый код — исполняемый объектный код (или данные), который существует в результате ошибки разработки программного обеспечения, но не может быть выполнен (код) или использован (данные) в какой-либо рабочей конфигурации целевой компьютерной среды. Он не прослеживается до системного или программного требования. Следующие исключения часто ошибочно классифицируются как мертвый код, но они необходимы для реализации требований/проекта: встроенные идентификаторы, защитные программные структуры для повышения надежности и деактивированный код, такой как неиспользуемые библиотечные функции. [Поскольку обзор на основе требований должен идентифицировать такой код как не прослеживаемый к функциональным требованиям, статический анализ кода должен идентифицировать такой код как недостижимый, а структурный анализ покрытия результатов тестирования на основе требований должен идентифицировать такой код как недостижимый, наличие неоправданного мертвого кода в проекте должно заставить задуматься об эффективности процессов разработки и проверки организации.]
  3. ^ Джей Томас (24 января 2017 г.). "Трассируемость требований формирует основу для тщательного тестирования программного обеспечения" . Получено 11 июня 2019 г. Сочетание трассируемости требований с анализом покрытия также может выявить области "мертвого кода" или кода, который никогда не выполняется. Этот код может быть в основном неудобным, но он также может представлять угрозу безопасности, если хакер может получить доступ и оттуда получить контроль. Это код, который невозможно отследить, и поэтому его следует удалить.
  4. ^ Консорциум MISRA (март 2013 г.). Руководство MISRA C:2012 по использованию языка C в критических системах. MIRA Limited . стр. 41. Получено 11.06.2019 . Правило 2.2. Не должно быть мертвого кода . Любая операция, которая выполняется, но удаление которой не повлияет на поведение программы, представляет собой мертвый код .
  5. ^ ab Адам Лэнгли (2014). «Ошибка SSL/TLS от Apple».
  6. ^ abc Ари ван Дёрсен (2014). «Изучаем ошибку безопасности #gotofail от Apple».
  7. ^ "sslKeyExchange.c - Исходный код для поддержки обмена ключами и обмена ключами сервера".
  8. ^ "MSC15-C . Не зависьте от неопределенного поведения". Университет Карнеги-Меллона. 2020. Получено 28 сентября 2020. Поскольку компиляторы не обязаны генерировать код для неопределенного поведения, эти поведения являются кандидатами на оптимизацию.
  9. ^ «Спецификация языка Java».