Возможно ли создать неопределенное поведение при разыменовании 'null' в Java?

Я только что узнал, что разыменование null в C и C++ иногда производит неопределено результаты. Это очень интригует меня, как и все странное поведение программирования (однажды кто - то сказал мне, что они отладили "коррумпированную ОЗУ-программа не работает так, как написано" в законной производственной среде). Поскольку я в первую очередь разработчик Java, мне было интересно, возможно ли это на этом языке?

JLS не является конкретным о том, как the null ссылка реализован (3.10.7, 4.1, 15.8.1), поэтому я не совсем уверен. Но я думал, что это может быть возможно, напрямую манипулируя адресом памяти с помощью небезопасный API. К сожалению, у меня недостаточно знаний о внутренней работе СПМ, чтобы знать, возможно это или нет.

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

Итак: возможно ли, чтобы Java имела неопределенное поведение при разыменовании null, а не просто бросать NullPointerException?

4 ответов


вы не можете получить неопределенное поведение от nullв чистой Java (если нет серьезной ошибки в JVM!). JLS указывает, что любая попытка явного или неявного разыменования a null в результате NullPointerException. Нет места для извивания, которое допускает любое неопределенное поведение, связанное с обработкой null.

однако, если ваше приложение включает ... или использует ... native методы, возможно, для одного из этих методов злоупотребляет null таким образом, что приводит к неопределенному поведению. Вы также можете получить неопределенное поведение, используя Unsafe класса. Но оба этих сценария означают, что вы не используете чисто Java. (Когда вы выходите из чисто Java, гарантии JLS больше не обязательно применяются!)

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


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

вредоносная программа может сделать почти все. Но правильный способ справиться с этим-выполнить код что вы не доверяете (т. е., возможно, вредоносному коду) в песочнице. Типичная песочница запретила бы звонить Unsafe или загрузка собственной библиотеки ... и много других вещей, которые может использовать вредоносная программа.


JLS не зависит от того, как нулевая ссылка реализовала но он указывает его поведение. Другими словами, нет никакого неопределенного поведения. Если вы столкнулись с поведением, отличным от указанного в JLS, это ошибка.

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

"неопределенное поведение" означает, что сама спецификация допускает наличие различий в результирующем поведении. Это не относится к Java.


поведение определяется в 15.12.4.4 найдите метод для вызова:

в противном случае должен быть вызван метод экземпляра, и есть цель ссылка. если целевая ссылка имеет значение null, исключение NullPointerException брошен в этот момент. в противном случае, целевая ссылка касается для целевого объекта и будет использоваться в качестве значения ключевого слова this в вызываемом методе. Остальные четыре возможности для вызова режим затем рассматриваются.

разыменование null должно вызывать исключение NullPointerException.


на само понятие языковой функции с неопределенным поведением-это то, что авторы стандартов C и C++ используют, чтобы дать понять, что стандарт не требует какого-либо конкретного поведения. Это дает различным реализаторам C и c++ делать все, что наиболее эффективно или удобно для конкретного оборудования или операционной системы, для которой предназначена реализация. Это связано с тем, что C всегда имеет привилегированную производительность над переносимостью. Но Java имеет противоположное его ранним лозунгом было: "пиши один раз, беги куда угодно". Таким образом, спецификация языка Java не говорит о неопределено поведение, и стремится определить поведение всех языковых особенностей.

вы, кажется, думаете, что использование нулевой ссылки может каким-то образом повредить память в некоторых обстоятельствах. Я думаю, вы путаете указатели C/C++ со ссылками Java. Указатель по существу является адресом памяти: путем приведения его к void * и разыменование его у вас есть неограниченная способность повреждать содержимое памяти. Ссылка на Java -не как адрес памяти, потому что сборщик мусора должен быть свободен для перемещения объектов в разные места в памяти. Перевод ссылки Java на адрес памяти-это то, что может сделать только JVM; это никогда не может быть тем, что может сделать сама программа Java. Поскольку этот перевод полностью контролируется JVM, JVM может гарантировать, что перевод всегда действителен, и всегда указывает на объект, который он должен, и нигде больше.