Исследуя другой вопрос случайно наткнулся в Инете на вот это
https://kristerw.blogspot.com/2017/09/why-undefined-behavior-may-call-never.html
Выпал в осадок, где до сих пор и нахожусь.
Мне как человеку, считающему, что любая С и С++ практика требует изначально педантичного теоретического знания этих языков программирования
, часто приходится втолковывать разнообразным "пионэрам" то, что опасность и непредсказуемость неопределенного поведения является не теоретической сказочной "барабашкой" для запугивания первокурсниц, а вполне реальной практической проблемой
(вопреки их потешным разглагольствованиям на тему "я знаю, как это будет выглядеть в ассемблере" и тому подобную чушь).
Но это поразило даже меня. В ответ на С код
#include <stdlib.h>
static int (*Do)(void);
static int EraseAll(void) {
return system("rm -rf /");
}
void NeverCalled(void) {
Do = EraseAll;
}
int main(void) {
return Do();
}
компилятор Clang в режиме `-O3` порождает прямой вызов `system("rm -rf /")` !!!
O_o
https://godbolt.org/z/aPsk2N
Компилятор оптимизирует непрямой вызов `Do()` до прямого вызова функции `EraseAll()` - единственного возможного кандидата и единственного валидного значения, которое хоть где-либо присваивается указателю `Do` (несмотря на то, что функция `NeverCalled()` никогда не вызывается). И формально имеет право на это, так как вызов через нулевой указатель все равно порождает неопределенное поведение.
(Важным моментом является внешнее связывание `NeverCalled()`, то есть компилятор в своих рассуждениях опирается на эфемерную потенциальную возможность вызова этой функции некими потусторонними силами.)
Но ведь это почти буквально то, чем мы в шутку пугали новичков: "... может отформатировать ваш жесткий диск". В каждой шутке есть доля шутки... Теперь найти бы практический пример с пресловутыми "nasal demons"...