Является ли разыменование неверных указателей законным, если преобразование lvalue-to-rvalue не происходит
Попробуй, как я мог, самый близкий ответ, который я видел, this, с двумя полностью противоположными ответами (!)
Вопрос прост, является ли это законным?
auto p = reinterpret_cast<int*>(0xbadface);
*p; // legal?
Мое отношение к делу
Итак, я пришел к выводу, что нет ничего явно, говоря, что это поведение undefined. Тем не менее я отчетливо помню, что некоторые платформы ловушки на косвенные ссылки для недействительных указателей. Что пошло не так с моими рассуждениями?
Ответы
Ответ 1
[basic.compound] говорит:
Каждое значение типа указателя является одним из следующих:
- указатель на объект или функцию (указывается, что указатель указывает на объект или функцию) или
- указатель за концом объекта ([expr.add]) или
- значение нулевого указателя ([conv.ptr]) для этого типа или
- неверное значение указателя.
В процессе устранения мы можем сделать вывод, что p
является недопустимым значением указателя.
[basic.stc] говорит:
Направление с помощью недопустимого значения указателя и передача недопустимого значения значение указателя для функции deallocation имеет поведение undefined. Любые другое использование недопустимого значения указателя имеет определенную реализацию поведение.
Как говорят, оператор косвенности выполняет косвенное обращение [expr.unary.op], я бы сказал, что выражение *p
вызывает UB независимо от того, используется ли результат или нет.
Ответ 2
... некоторые платформы ловушки для косвенных ссылок для недействительных указателей.
Большинство ловушек ловушки недействительного доступа к адресам. Это никоим образом не противоречит этой проблеме. Вопрос о том, что происходит в *p;
, сводится к тому, происходит ли попытка на самом деле получить неверный адрес или нет.
Вопрос об извлечении очень похож на основная проблема 232 (косвенность через нулевой указатель). Как вы уже указали, *p;
является отброшенным значением выражения, и как таковой преобразование lvalue-to-rvalue ( "выборка" ):
Tom Plum:
... это только акт "выборки", преобразования lvalue-to-rvalue, который вызывает неправильное поведение или undefined.
И впоследствии:
Примечания от совещания в октябре 2003 года:
Мы согласились, что подход в стандарте выглядит нормально: p = 0; *p;
по сути, не является ошибкой. Преобразование lvalue-to-rvalue дало бы ему undefined.
Что касается того, создает ли или нет reinterpret_cast<int*>(0xbadface)
допустимый указатель, действительно, в реализациях со строгой безопасностью указателя, это не будет безопасным образом указателем, и как таковой является недопустимым, и любое его использование - UB.
Но в случае расслабленной безопасности указателя результирующий указатель действителен (в противном случае было бы невозможно использовать указатели, возвращаемые из двоичных библиотек и компонентов написанных на C или других языках).