Обновить
0

Пользователь

0,6
Рейтинг
4
Подписчики
Отправить сообщение

Ещё раз - дайте мне кусок стандартам, который подтверждает, что писать в случайную память - это UB

И тем не менее он генерируется. Чудеса, не иначе

Ну ничего, завезут скоро std::start_lifetime_as и заживём!

P.S.

В нормальных языках спорят о каких-то реальных проблемах, какие-то там подходы к решению тех или иных задач, но самые жаркие споры в С++ комьюнити до сих пор о самом С++. Гспди, на что я трачу жизнь...

Прошу прощения, но я спать. Я уже час как хочу лечь, но этот бессмысленный спор меня затянул :)

Так стоп. После того, как я скастил 0x3 к указателю, с точки зрения синтаксиса программы последующее разыменование - это обращение к объекту.

У компилятора нет никакой возможности доказать, что там этого объекта нет. Этот объект может жить в другом TU. Следовательно компилятор ничего не остаётся, кроме как поверить мне на слово.

Я не согласен. Конечно синтаксически С++ достаточно прост (хотя и Haskell не сказал бы я, что сложен). Основная убер фича С++ - это UB. Писать код без него - подобно искусству каллиграфии. Haskell может быть сложен с той точки зрения, что требует некоторого математического бекграунда для понимания. Но с точки зрения способов выстрелить в себе в ногу С++ впереди всей планеты.

Что значит речь не о том? Я компилятору вполне внятно сказал "по этому адресу лежит объект с типом volatile int, я хочу в него записать значение, и меня вообще не волнует, что ты об этом думаешь". И компилятор обязан сгенерировать код. Без вариантов. Компилятор компилирует один TU, и может тупо не видеть этот int. Но будет он там или нет - дело даже не компилятора. Компилятор не располагает объекты в бинаре. Линковщик это делает.

В данном случае компилятор может вообще выкинуть этот код, если он докажет, что там лежит не инт.

Мне лень ходить в стандарт, поэтому я схожу на cppreference.

volatile object - an object whose type is volatile-qualified... volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access

А вот это — нет. В валидной программе на C++ UB нет.

Да. Но это ведь не означает, что внутри UB нет валидной программы на С++ :)

А я утверждаю, что UB - это прежде всего behaviour. Компилятор всегда на строчку `*((volatile int*)0x3) = 1` сгенерирует один и тот же код. Он не может не сгенерировать код записи в память, когда его об этом явно просят. С точки зрения компилятора поведение очень defined.

А вот во время исполнения мы можем получить как defined, так и undefined поведение. Если мы создали все условия, чтобы по адресу 0x3 всё было валидно, значит поведение всегда будет well-defined. В ином случае - да UB.

При таком взгляде на проблему, линкер скрипты вполне себе обеспечивают гарантированно определённое поведение.

Не какой-то, а конкретный код генерируется. UB происходит не на стадии компиляции, а на стадии исполнения программы. Если по адресу записываемому адресу на момент исполнения программы всегда живёт объект нужного типа, абсолютно валидно туда что-то писать. До момента старта программы UB нет.

Вы просто пессимист. Ввиду того, что UB включает в себя всё что угодно, включая валидную программу на С++, можно сказать, что любая программа с UB написана на С++ :)

Кроме того, есть правила, описывающие, что конкретно надо сделать, чтобы там было что-то валидное. Если вы этого не сделали, то там ничего валидного нет.

Да, но не сказано ГДЕ нужно это сделать. Я могу это сделать в любом TU в программе. Это никак не меняет того факта, что если я разместил какой-то int где угодно в программе по адресу 0x3 и этот int всё еще там, пока я пишу в адрес 0x3 - это абсолютно валидный код, ничего не нарушающий, не создающий UB, и т.д. и т.п.

В С++ нет ничего синтаксически некорректного в желании записать что-то по любому адресу. Стандарт говорит: "Если по этому адресу лежит то, что ты туда пишешь, то всё нормально". А вот если "там лежит не то, что ты туда пишешь" или "там ничего не лежит", то тут UB.

Но я же могу подключить её в С++? Вся эта магия - она в макросах, так что существует в заголовочном файле.

В таком случае никто в Embedded в принципе не программирует на С++)

И компилятор, который ничего не знает ни про какие ld-скрипты, вполне имеет право решить, что по этому адресу ничего нет.

Окей.

*((volatile int*)0x3) = 0xDEADBEEF

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

Да гспди, загляните в HAL-библиотеку для STM32. Там всё в таком коде, пищущим по магическим адресам.

То и значит, что "где угодно". Как пример: я могу написать в любом TU int anything, потом написать ld-скрипт, который переменную с именем anything расположит ровно по адресу 0x3. И будет её всегда туда располагать.

Соответственно на старте программы и проинициализируется этот адрес. Он будет валидный и туда можно будет писать.

Здесь - нигде. Но в С++ он мог быт начат где угодно) Писать по вот таким рандомным адресам - обычное дело в embedded.

Информация

В рейтинге
2 277-й
Зарегистрирован
Активность