Понимаете, все эти рассуждения на тему "оно, конечно, UB, но на практике ничего страшного не будет" исходят из предположения, что компилятор сгенерирует примерно тот код, что вы и ожидаете, а дальше что-то может пойти не так уже из-за этого кода - либо он приведёт к segfault, либо к нарушению выравнивания, и т.д.
Но оптимизатор это такая штука, которая очень любит менять ваш код, если это не меняет наблюдаемого поведения, и если ему кажется, что замена позволяет получить какой-то выигрыш.
Например, здесь:
void f(int *p) {
if(!p) return;
if(p)
g();
else
h();
}
Вторая проверка и вызов h будут выкинуты, потому что это не меняет наблюдаемого поведения - оптимизатор точно знает, что строка с вызовом h просто никогда не сможет выполниться. И точно так же он может (будет) поступать, если встретит код, которого не должно быть, ибо по стандарту этот код вызывает UB - он посчитает, что по каким-то причинам до исполнения этого кода дело просто не дойдёт. А если всё таки дойдёт, то оптимизатору абсолютно фиолетово, что получится - на то оно и UB, и погромист ССЗБ. Что именно случится из-за выкидывания кода, и какие ещё выводы сделает оптимизатор для остального кода, при условии, что ветка с UB выкинута - угадать невозможно, вплоть до схлопывания всей программы в один ret.