stringtranslate.com

Нулевой указатель

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

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

Поскольку нулевой указатель не указывает на значимый объект, попытка доступа к данным, хранящимся в этой (недопустимой) ячейке памяти, может вызвать ошибку во время выполнения или немедленный сбой программы. Это ошибка нулевого указателя . Это один из наиболее распространенных типов недостатков программного обеспечения [1] , и Тони Хоар , представивший эту концепцию, назвал его «ошибкой на миллиард долларов».

С

В C два нулевых указателя любого типа гарантированно сравниваются равными. [2] Макрос препроцессора NULLопределяется как определяемая реализацией константа нулевого указателя в , [3] которая в C99 может быть портативно выражена как , целочисленное значение, преобразованное в тип (см. указатель на тип void ). [4] Стандарт C не говорит, что нулевой указатель — это то же самое, что указатель на адрес памяти  0, хотя на практике это может быть так. Разыменование нулевого указателя является неопределенным поведением в C, [5] , и соответствующая реализация может предполагать, что любой разыменованный указатель не является нулевым.<stdlib.h>((void *)0)0 void*

На практике разыменование нулевого указателя может привести к попытке чтения или записи из памяти , которая не отображается, что приведет к ошибке сегментации или нарушению доступа к памяти. Это может проявиться в виде сбоя программы или трансформироваться в программное исключение , которое может быть перехвачено программным кодом. Однако существуют определенные обстоятельства, когда это не так. Например, в реальном режиме x86 адрес доступен для чтения, а также обычно доступен для записи, и разыменование указателя на этот адрес является совершенно допустимым, но обычно нежелательным действием, которое может привести к неопределенному, но не приводящему к сбою поведению приложения. Бывают случаи, когда разыменование указателя на нулевой адрес является намеренным и четко определенным; например, код BIOS , написанный на C для 16-битных устройств x86 реального режима, может записывать таблицу дескрипторов прерываний (IDT) по физическому адресу 0 машины путем разыменования нулевого указателя для записи. Компилятор также может оптимизировать разыменование нулевого указателя, избегая ошибки сегментации, но вызывая другое нежелательное поведение. [6]0000:0000

С++

В C++, хотя NULLмакрос был унаследован от C, традиционно предпочиталось использовать целочисленный литерал нуля для представления константы нулевого указателя. [7] Однако в C++11 появилась явная константа nullptrи тип нулевого указателя nullptr_t, которые будут использоваться вместо этого.

Другие языки

В некоторых средах языков программирования (например, по крайней мере в одной собственной реализации Lisp) значение , используемое в качестве нулевого указателя (вызываемое вnil Lisp ) , на самом деле может быть указателем на блок внутренних данных, полезных для реализации (но не доступен явно из пользовательских программ), что позволяет использовать один и тот же регистр в качестве полезной константы и быстрого способа доступа к внутренним компонентам реализации. Это известно как nilвектор.

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

Языки программирования используют разные литералы для нулевого указателя . В Python, например, нулевое значение называется None. В Паскале и Swift вызывается нулевой указатель nil. В Эйфеле это называется voidссылкой.

Нулевое разыменование

Поскольку нулевой указатель не указывает на значимый объект, попытка разыменования (т. е. доступа к данным, хранящимся в этом месте памяти) с нулевым указателем обычно (но не всегда) приводит к ошибке во время выполнения или немедленному сбою программы. MITRE называет ошибку нулевого указателя одной из наиболее часто используемых уязвимостей программного обеспечения. [8]

смягчение последствий

Существуют методы, облегчающие отладку разыменования нулевого указателя. [11] Бонд и др. [11] предлагают модифицировать виртуальную машину Java (JVM), чтобы отслеживать распространение нулей.

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

Если язык предоставляет или использует указатели, которые в противном случае могли бы стать недействительными, можно смягчить или избежать нулевых разыменований во время выполнения, обеспечив проверку во время компиляции с помощью статического анализа или других методов, с растущим движением в сторону синтаксической помощи со стороны таких функций языка, как те, что встречаются в современных версиях языка программирования Eiffel , [12] D , [13] и Rust . [14]

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

История

В 2009 году Тони Хоар заявил [15] , что он изобрел нулевую ссылку в 1965 году как часть языка ALGOL W. В статье 2009 года Хоар описывает свое изобретение как «ошибку на миллиард долларов»:

Я называю это своей ошибкой на миллиард долларов. Это было изобретение нулевой ссылки в 1965 году. В то время я разрабатывал первую комплексную систему типов для ссылок на объектно-ориентированном языке (ALGOL W). Моя цель состояла в том, чтобы гарантировать, что любое использование ссылок должно быть абсолютно безопасным, с автоматической проверкой, выполняемой компилятором. Но я не смог устоять перед искушением добавить нулевую ссылку просто потому, что это было так легко реализовать. Это привело к бесчисленным ошибкам, уязвимостям и сбоям в системе, которые, вероятно, причинили боль и ущерб на миллиард долларов за последние сорок лет.

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

Примечания

  1. ^ «CWE-476: Разыменование нулевого указателя» . МИТРА .
  2. ^ ISO/IEC 9899, ​​пункт 6.3.2.3, параграф 4.
  3. ^ ISO/IEC 9899, ​​пункт 7.17, параграф 3: NULL... который расширяется до определяемой реализацией константы нулевого указателя...
  4. ^ ISO/IEC 9899, ​​пункт 6.3.2.3, параграф 3.
  5. ^ ab ISO/IEC 9899, ​​пункт 6.5.3.2, параграф 4, особенно. сноска 87.
  6. ^ Латтнер, Крис (13 мая 2011 г.). «Что каждый программист на C должен знать о неопределенном поведении № 1/3». blog.llvm.org . Архивировано из оригинала 14 июня 2023 г. Проверено 14 июня 2023 г.
  7. ^ Страуструп, Бьярн (март 2001 г.). «Глава 5: Спецификатор (§5.4) предотвращает случайное переопределение и гарантирует, что его можно использовать там, где требуется константа.». Язык программирования C++ (14-е издание 3-го изд.). США и Канада: Аддисон-Уэсли. п. 88. ИСБН
    constNULLNULL 0-201-88954-4.
  8. ^ «CWE-476: Разыменование нулевого указателя» . МИТРА .
  9. ^ Язык программирования Objective-C 2.0 , раздел «Отправка сообщений в ноль».
  10. ^ «Разыменование нулевого указателя ядра OS X в AppleGraphicsDeviceControl»
  11. ^ аб Бонд, Майкл Д.; Нетеркот, Николас; Кент, Стивен В.; Гайер, Сэмюэл З.; МакКинли, Кэтрин С. (2007). «Отслеживание плохих яблок». Материалы 22-й ежегодной конференции ACM SIGPLAN по системам и приложениям объектно-ориентированного программирования — OOPSLA '07 . п. 405. дои : 10.1145/1297027.1297057. ISBN 9781595937865. S2CID  2832749.
  12. ^ «Безопасность Бездны: Предыстория, определение и инструменты» . Проверено 24 ноября 2021 г.
  13. ^ Бартош Милевский. «Язык программирования SafeD-D» . Проверено 17 июля 2014 г.
  14. ^ «Бесстрашная безопасность: безопасность памяти». Архивировано из оригинала 8 ноября 2020 года . Проверено 4 ноября 2020 г. .
  15. ^ Тони Хоар (25 августа 2009 г.). «Нулевые ссылки: ошибка на миллиард долларов». InfoQ.com.

Рекомендации