Случай из реального проекта, код ~10-летней выдержки. Когда-то давно забыл добавить return в функцию, где имеется хитрая условная компиляция. Долгое время всё нормально работало, а сегодня вот пересобрал проект и поимел весёлых проблем. При проигрывании звука сегфолтилось, хотя вроде как в коде всё было нормально. Старые версии (собранные старым GCC) не сегфолтились. При отключенной оптимизации сегфолта тоже не было. Что тут можно ещё сказать? Спасибо Сталлману за gdb, сильно удивился когда увидел вызов якобы вырезанной функции в нём. Ну и главное: читайте и анализируйте Warning’и, господа! Минимальный пример:
$ cat dead_code.cpp
// dead_code.cpp
#include <cstdio>
int stub_0();
int pxt_PlayWithCallback(int chan, int slot, char loop, void (*FinishedCB)(int, int));
int pxt_Play(int chan, int slot, char loop) {
#ifdef _PLS_NO_DEAD_CODE
if (stub_0()) {
fprintf(stderr, "!!!!! GOOD CODE !!!!!\n");
}
#else
return pxt_PlayWithCallback(chan, slot, loop, NULL);
#endif
}
int pxt_PlayWithCallback(int chan, int slot, char loop, void (*FinishedCB)(int, int)) {
fprintf(stderr, "????? DEAD CODE ?????\n");
return stub_0();
}
int stub_0() { return 42; }
int main(int argc, char *argv[]) {
return pxt_Play(-1, 20, 0);
}
// OK:
$ g++ dead_code.cpp
$ ./a.out
????? DEAD CODE ?????
// OK:
$ g++ -D_PLS_NO_DEAD_CODE dead_code.cpp
$ ./a.out
!!!!! GOOD CODE !!!!!
// WTF?:
$ g++ -O2 -D_PLS_NO_DEAD_CODE dead_code.cpp
$ ./a.out
!!!!! GOOD CODE !!!!!
????? DEAD CODE ?????
Segmentation fault (core dumped)
// WTF???:
$ g++ -O3 -D_PLS_NO_DEAD_CODE dead_code.cpp
$ ./a.out
!!!!! GOOD CODE !!!!!
!!!!! GOOD CODE !!!!!
...
!!!!! GOOD CODE !!!!!
!!!!! GOOD CODE !!!!!
Segmentation fault (core dumped)
А ведь довольно интересный простор за этим может скрываться. Ну право ведь, забыли return проставить, компилятор же по-дефолту return 0 впихнёт, верно? А я в этом был уверен.
P.S.
// Имеется предупреждение по-дефолту, отсутствует ret в конце функции, провал и сегфолт.
$ gcc --version
gcc (GCC) 10.2.1 20200723 (Red Hat 10.2.1-1)
// Предупреждение только с -Wall, ret в конце функции имеется, нет провала и сегфолта.
$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
P.P.S. поиграться с компиляторами:
C++: https://gcc.godbolt.org/z/7ne8PM
C: https://gcc.godbolt.org/z/b6vqbK
Может кто-нибудь из профи подробно объяснить механизм такого поведения? Спасибо.
См. комментарии и ссылки в теме.






