Compiler Bug Causes Compiler Bug: How a 12-Year-Old G++ Bug Took Down Solidity
Краткий обзор
- Проблема: компилятор Solidity (solc) падает на Ubuntu 22.04 при компиляции корректного кода.
- Причина: сочетание трёх факторов
- 12-летний баг G++ (< 14) в разрешении перегрузок.
- Устаревший паттерн сравнения в Boost.
- Новые правила симметричных сравнений C++20.
Цепочка событий
- Баг G++ (2012, GCC-53499): при
boost::rational<T> == 0
компилятор до 14-й версии выбирает нечлен-шаблон вместо член-шаблона. - C++20 добавляет автоматическую перестановку аргументов:
0 == rational<T>
→rational<T> == 0
. - Boost 1.74 предоставляет обе версии оператора, что приводит к бесконечной рекурсии и переполнению стека.
Минимальный пример
template<typename T>
struct rational {
template<class U>
bool operator==(const U&) const { return true; }
};
template<class U, class T>
bool operator==(const rational<T>&, const U&) { return false; }
int main() {
rational<int> r;
return r == 0; // g++11 выбирает free-функцию
}
Как починить
- Обновить GCC ≥ 14 или Clang, или
- Собрать Solidity без C++20 (
-std=c++17
), или - Патч Boost/использовать свежий Boost ≥ 1.82.
Итог
Ни один компонент по отдельности не «сломан», но их комбинация приводит к крашу компилятора на валидном коде.
Комментарии (66)
- Уязвимость в компиляторе Solidity/GCC показала, как «мелкие» баги через слои абстракции могут привести к исполнению произвольного кода (стиль xz-backdoor).
- Участники критикуют непрерывное усложнение C++: новые синтаксические «плюшки» вроде spaceship-operator <=> делают язык перегруженным, а компиляторы хрупкими.
- Предложено «перезапустить» C++ как Python 2→3, чтобы старый код не компилировался новыми компиляторами и разработчики переписывали его на современный подмножество (cppfront).
- Смарт-контракты называют плохой идеей: код как источник истины неизбежно содержит баги, что уже стоило сотен миллионов долларов.
- Лицензия SPDX в 6 строках примера вызвала иронию: Solidity требует её, но UNLICENSED выглядит нелепо и не защищает от обучения ИИ.