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

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

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

C

В C, два нулевых указателя любого типа гарантированно сравниваются как равные.[1] Макрос препроцессора НОЛЬ определяется как константа нулевого указателя, определяемая реализацией,[2] который в C99 можно переносимо выразить как целочисленное значение 0 преобразован в тип пустота* (указатель на пустота ).[3] Стандарт C не говорит, что нулевой указатель совпадает с указателем на адрес памяти 0, хотя на практике это может быть так. Разыменование нулевой указатель неопределенное поведение в C,[4] и соответствующая реализация может предполагать, что любой указатель, ссылка на который разыменована, не является нулевым.

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

C ++

В C ++, а НОЛЬ был унаследован от C, целочисленный литерал для нуля традиционно предпочитался представлять константу нулевого указателя.[5] Тем не мение, C ++ 11 ввел явную константу нулевого указателя nullptr будет использоваться вместо этого.

Другие языки

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

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

В языках программирования используются разные литералы для нулевой указатель. В Python, например, нулевое значение называется Никто. В Паскаль и Быстрый, нулевой указатель называется ноль. В Эйфель, это называется пустота ссылка.

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

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

  • В C разыменование нулевого указателя неопределенное поведение.[4] Многие реализации приводят к тому, что такой код приводит к остановке программы с нарушение доступа, поскольку в качестве представления нулевого указателя выбирается адрес, который никогда не выделяется системой для хранения объектов. Однако такое поведение не универсально. Это также не гарантируется, поскольку компиляторам разрешено оптимизировать программы в предположении, что они не имеют неопределенного поведения.
  • В Delphi и многих других реализациях Паскаля константа ноль представляет собой нулевой указатель на первый адрес в памяти, который также используется для инициализации управляемых переменных. Разыменование его вызывает внешнее исключение ОС, которое отображается на экземпляр исключения Pascal EAccessViolation, если модуль System.SysUtils связан в предложении uses.
  • В Java доступ к пустой ссылке запускает Исключение нулевого указателя (NPE), который может быть обнаружен кодом обработки ошибок, но предпочтительной практикой является обеспечение того, чтобы такие исключения никогда не возникали.
  • В .NET доступ к нулевой ссылке вызывает исключение NullReferenceException. Хотя их перехват обычно считается плохой практикой, этот тип исключения может быть перехвачен и обработан программой.
  • В Цель-C, сообщения могут быть отправлены ноль объект (который является нулевым указателем), не вызывая прерывания программы; сообщение просто игнорируется, а возвращаемое значение (если есть) ноль или же 0, в зависимости от типа.[6]
  • До введения SMAP, ошибка разыменования нулевого указателя может быть использована путем сопоставления pagezero в нападавшего адресное пространство и, следовательно, заставляет нулевой указатель указывать на эту область. Это могло привести к выполнение кода в некоторых случаях.[7]

Смягчение

Существуют методы, облегчающие отладку разыменования нулевого указателя.[8][9] Бонд и др.[8] Предлагаем изменить JVM, чтобы отслеживать нулевое распространение. Идея системы Casper[9] заключается в использовании преобразования исходного кода для отслеживания этого распространения без изменения JVM. В некоторых случаях можно автоматически сгенерировать патч для исправления исключений с нулевым указателем.[10]

История

В 2009 Тони Хоар (C.A.R. Hoare) заявил[11]что он изобрел нулевую ссылку в 1965 году как часть АЛГОЛ W язык. В этой ссылке 2009 года Хоар описывает свое изобретение как «ошибку на миллиард долларов»:

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

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

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

Цитаты

  1. ^ ISO / IEC 9899, п. 6.3.2.3, п. 4.
  2. ^ ISO / IEC 9899, п. 7.17, п. 3: NULL ... который расширяется до константы нулевого указателя, определяемой реализацией ...
  3. ^ ISO / IEC 9899, п. 6.3.2.3, п. 3.
  4. ^ а б ISO / IEC 9899, пункт 6.5.3.2, пункт 4, особенно сноска 87.
  5. ^ Страуструп, Бьярне (Март 2001 г.). "Глава 5:
    В const квалификатор (§5.4) предотвращает случайное переопределение НОЛЬ и гарантирует, что НОЛЬ может использоваться там, где требуется константа. ". Язык программирования C ++ (14-е издание 3-го изд.). США и Канада: Аддисон – Уэсли. п.88. ISBN  0-201-88954-4.
  6. ^ Язык программирования Objective-C 2.0, раздел «Отправка сообщений на ноль».
  7. ^ Разыменовывание NULL-указателя уязвимого ядра OS X в AppleGraphicsDeviceControl
  8. ^ а б Бонд, Майкл Д .; Nethercote, Николас; Кент, Стивен У .; Guyer, Samuel Z .; МакКинли, Кэтрин С. (2007). «Отслеживание плохих яблок»: 405. Дои:10.1145/1297027.1297057. Цитировать журнал требует | журнал = (помощь)
  9. ^ а б Корню, Бенуа; Барр, Эрл Т .; Сейнтюрье, Лайонел; Монперрус, Мартин (2016). "Casper: автоматическое отслеживание нулевых разыменований на начало со следами причинности". Журнал систем и программного обеспечения. 122: 52–62. Дои:10.1016 / j.jss.2016.08.062. ISSN  0164-1212.
  10. ^ Дюрье, Томас; Корню, Бенуа; Сейнтюрье, Лайонел; Монперрус, Мартин (2017). «Динамическое создание исправлений для исключений с нулевым указателем с использованием метапрограммирования» (PDF). 24-я Международная конференция по анализу, эволюции и реинжинирингу программного обеспечения, IEEE, 2017 (SANER). IEEE: 349–358. Дои:10.1109 / SANER.2017.7884635. ISBN  978-1-5090-5501-2.
  11. ^ Тони Хоар (2009-08-25). «Нулевые ссылки: ошибка в миллиард долларов». InfoQ.com.

Источники

  • Объединенный технический комитет ISO / IEC JTC 1, Подкомитет SC 22, Рабочая группа WG 14 (2007-09-08). Международный стандарт ISO / IEC 9899 (PDF) (Проект комитета).CS1 maint: несколько имен: список авторов (связь)