habrahabr

Линус Торвальдс: GCC 4.9.0 «неизлечимо сломан»

  • вторник, 29 июля 2014 г. в 03:10:59
http://habrahabr.ru/post/231243/

Компиляторы последних поколений стали настолько умными, что практически самостоятельно генерируют код, оптимизируя всё подряд. Иногда это приводит к неприятным последствиям.

В процессе подготовки очередного релиз-кандидата в ядре Linux 3.16 выяснилось совершенно непредсказуемое поведение функции балансировки нагрузки в Linux 3.16-rc6. В списке рассылки для разработчиков ядра двое авторов прислали сообщения о разных багах, хотя у них могла быть общая природа.

Линус Торвальдс внимательно разобрался в вопросе и ёмко ответил одному из сообщивших о баге: «Ok, я посмотрел на генерацию кода, и твой компилятор — чистое и полное дерьмо».

Продолжение письма Линуса.

Я включил Якуба в список рассылки, потому что gcc-4.9.0 кажется неизлечимо сломанным.

Вот смотри, твой компилятор делает совершенно невообразимые вещи с вытеснением (спиллингом) данных, включая вытеснение константы. Господи, да этому компилятору нельзя ещё выходить из детского сада. Мы говорим о дебиле, которого в детстве уронили головой — такой здесь уровень задержки в развитии:

...
movq $load_balance_mask, -136(%rbp) #, %sfp
subq $184, %rsp #,
movq (%rdx), %rax # sd_22(D)->parent, sd_parent
movl %edi, -144(%rbp) # this_cpu, %sfp
movl %ecx, -140(%rbp) # idle, %sfp
movq %r8, -200(%rbp) # continue_balancing, %sfp
movq %rax, -184(%rbp) # sd_parent, %sfp
movq -136(%rbp), %rax # %sfp, tcp_ptr__
#APP
add %gs:this_cpu_off, %rax # this_cpu_off, tcp_ptr__
#NO_APP
... 

Обратите внимание на содержимое -136(%rbp). Реально. Это непосредственная константа, которую компилятор вытеснил.

Кто-то должен оформить это как баг gcc. Потому что это, чёрт возьми, офигенно сумасшедшая хрень.

Но эту часть с вытеснением константы можно считать «слишком тупой, чтобы жить». Настоящий баг здесь:

movq $load_balance_mask, -136(%rbp) #, %sfp
subq $184, %rsp #,

Тут gcc создаёт стековый фрейм после его использования для сохранения константы гораздо дальше стекового фрейма.

В любом случае, подчёркивает Линус, это не баг ядра. Он предлагает создать официальное предупреждение для всех ни в коем случае не использовать компилятор gcc-4.9.0, а «пользователям Debian, вероятно, следует сделать даунгрейд их новенького классного компилятора».



P.S. Комментарий хорошо информированного пользователя a5b: Открытый Линусом баг 61904 (gcc bugzilla) был закрыт как дубликат бага 61801. 61801 существовал в версиях gcc с 4.5.0 по 4.8.3, 4.9.0 и 4.9.1 (однако до 4.9.0 ошибка не приводила к спиливанию константы в коде load_balance). Исправлено начиная с 4.8.4, 4.9.2, 4.10.0. Патч — одна строчка в sched_analyze_2.