У меня возникает странная проблема с GCC (4.6.4, Ubuntu 12.04), иногда я использую ее для компиляции огромного проекта (сотни файлов и сотни тысяч строк кода), но я недавно что-то заметил. После некоторых компиляций (кажется, случается случайным образом), я получаю определенный фрагмент кода, скомпилированный по-разному и ошибочно, вызывая поведение undefined в моем коде:
class someDerivedClass : public someBaseClass
{
public:
struct anotherDerived : public anoterBaseClass
{
void SomeMethod()
{
someMember->someSetter(2);
}
}
}
Где "someSetter" определяется как:
void someSetter(varType varName) { someOtherMember = varName; }
Обычно SomeMethod() скомпилируется в:
00000000019fd910 mov 0x20(%rdi),%rax
00000000019fd914 movl $0x2,0x278c(%rax)
00000000019fd91e retq
Но иногда он получает (неправомерно) скомпилированный для:
000000000196e4ee mov 0x20(%rdi),%rax
000000000196e4f2 movl $0x2,0x27d4(%rax)
000000000196e4fc retq
Сетчатка, похоже, встраивается, вероятно, из-за флагов компиляции -O2:
-std=c++11 -m64 -O2 -ggdb3 -pipe -Wliteral-suffix -fpermissive -fno-fast-math -fno-strength-reduce -fno-delete-null-pointer-checks -fno-strict-aliasing
но это не проблема. Реальная проблема - это смещение члена someOtherMember, 0x278c правильно (первый случай), но 0x27d4 неверен (второй случай), и это, очевидно, заканчивается модификацией совершенно другого члена класса. Почему это происходит? Что мне не хватает? (также, я не знаю, какую другую соответствующую информацию я могу опубликовать, поэтому спросите). Помните, что это происходит при повторной компиляции проекта (полная перекомпиляция или просто компиляция только измененных файлов), без, изменение затронутого файла (или файлов с использованием используемых классов). Например, просто добавление простого printf() в полностью несвязанный файл может вызвать это поведение или заставить его уйти, когда это произойдет. Должен ли я просто обвинять это в -O2? Я не могу воспроизвести его без флага оптимизации, потому что это происходит абсолютно случайно. Я использую make -j 8, это происходит даже после очистки папки сборки, но не обязательно происходит только после этого