Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

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

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

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

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

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

Причины [ править ]

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

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

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

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

Примеры [ править ]

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

int  foo  ( int  X ,  int  Y ) {  вернуть  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] :

статический  OSStatus SSLVerifySignedServerKeyExchange ( SSLContext  * ctx ,  bool  isRsa ,  SSLBuffer  signedParams ,  uint8_t  * подпись ,  UInt16  signatureLen ) {  OSStatus  err ;  ...  если  (( ERR  =  SSLHashSHA1 . обновление ( & hashCtx ,  & serverRandom ))  ! =  0 )  Гото  неудачу ;  если  (( ERR  =  SSLHashSHA1 . обновление ( & hashCtx ,  & signedParams ))  ! =  0 )  Гото  неудачу ; перейти к неудаче ; если (( err = SSLHashSHA1 . final ( & hashCtx      ,  & hashOut ))  ! =  0 )  goto  fail ;  ... сбой :  SSLFreeBuffer ( & signedHashes );  SSLFreeBuffer ( & hashCtx );  return  err ; }

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

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

C ++ [ править ]

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

Анализ [ править ]

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

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

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

int  N  =  2  +  1 ;if  ( N  ==  4 ) {  / * недоступен * / }

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

двойной  X  =  sqrt ( 2 );if  ( X  >  5 ) {  / * недоступен * / }

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

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

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

См. Также [ править ]

  • Покрытие кода
  • Резервный код
  • Мертвый код
  • Код Оксбоу

Ссылки [ править ]

  1. ^ Debray, Saumya K .; Эванс, Уильям; Мут, Роберт; Де Саттер, Бьорн (1 марта 2000 г.). «Компиляторные методы для сжатия кода». Транзакции ACM по языкам и системам программирования . 22 (2): 378–415. CiteSeerX 10.1.1.43.7215 . DOI : 10.1145 / 349214.349233 . S2CID 6129772 .  
  2. ^ Рекомендации по программному обеспечению RTCA / DO-178C при сертификации бортовых систем и оборудования . RTCA, Inc. 2011. стр. 112 . Проверено 11 июня 2019 .Мертвый код - исполняемый объектный код (или данные), который существует в результате ошибки разработки программного обеспечения, но не может быть выполнен (код) или использован (данные) в любой операционной конфигурации целевой компьютерной среды. Это не связано с требованиями к системе или программному обеспечению. Следующие исключения часто ошибочно классифицируются как мертвый код, но они необходимы для реализации требований / дизайна: встроенные идентификаторы, защитные программные структуры для повышения надежности и деактивированный код, например неиспользуемые библиотечные функции. [Поскольку проверка на основе требований должна идентифицировать такой код как неотслеживаемый по функциональным требованиям, статический анализ кода должен идентифицировать такой код как недоступный, а анализ структурного покрытия результатов тестирования на основе требований должен идентифицировать такой код как недостижимый,наличие неоправданно мертвого кода в проекте должно вызвать необходимость рассмотрения эффективности процессов разработки и проверки организации.]
  3. ^ Джей Томас. «Прослеживаемость требований формирует основу для тщательного тестирования программного обеспечения» . Проверено 11 июня 2019 . Сочетание прослеживаемости требований с анализом покрытия также может выявить области «мертвого кода» или кода, который никогда не выполняется. Этот код в основном может доставлять неудобства, но он также может быть угрозой безопасности, если хакер может получить доступ и оттуда получить контроль. Это код, который нельзя отследить, и поэтому его следует исключить.
  4. ^ MISRA Consortium (март 2013). MISRA C: 2012 Рекомендации по использованию языка C в критических системах . МИРА Лимитед . п. 41 . Проверено 11 июня 2019 . Правило 2.2: не должно быть мертвого кода . Любая выполняемая операция, удаление которой не повлияет на поведение программы, представляет собой мертвый код .
  5. ^ а б Адам Лэнгли (2014). «Ошибка SSL / TLS от Apple» .
  6. ^ а б в Ари ван Дерсен (2014). «Учимся на ошибке безопасности Apple #gotofail» .
  7. ^ "sslKeyExchange.c - Исходный код для поддержки обмена ключами и обмена ключами сервера" .
  8. ^ «MSC15-C. Не зависеть от неопределенного поведения» . Университет Карнеги Меллон. 2020 . Проверено 28 сентября 2020 . Поскольку компиляторы не обязаны генерировать код для неопределенного поведения, эти варианты поведения являются кандидатами на оптимизацию.
  9. ^ «Спецификация языка Java» .
  • Аппель, А.В. 1998 Современная реализация компилятора на Java. Издательство Кембриджского университета.
  • Мучник С.С. 1997 Расширенный дизайн и реализация компилятора. Морган Кауфманн.