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 выглядит нелепо и не защищает от обучения ИИ.
Booting 5000 Erlangs on Ampere One 192-core
Ampere One 192-ядерный сервер, 1 ТБ ОЗУ, цель — запустить максимум виртуальных IoT-устройств на Nerves.
Прошлый раз добрались до 500 экземпляров; теперь с KVM и новым загрузчиком little_loader от Frank Hunleth удалось 5000 одновременных виртуальных ARM64-машин.
little_loader — минимальный ARM64-бутлоадер, читающий переменные u-boot, загружающий ядро Linux и сохраняющий механизмы A/B-обновлений Nerves.
Что изменилось
- KVM/HVF ускоряет старт до 1-2 с и экономит ≈ 500 МБ ОЗУ на гость.
- EL1 вместо EL2: EL2 нужен для вложенной виртуализации, нам не требуется.
- Баг компиляции: release-сборка зависает, debug-версия работает (GCC 15, вероятно, чинит).
Команда запуска (упрощённый пример):
qemu-system-aarch64 \
-machine virt,accel=kvm \
-cpu host -smp 1 -m 150M \
-kernel little_loader.elf \
-netdev user,id=eth0 \
-device virtio-net-device,netdev=eth0 \
-drive if=none,file=disk.img,format=raw,id=vdisk \
-device virtio-blk-device,drive=vdisk \
-nographic
Итог: 5000 «эрлангов» на 192 ядрах, 1 ТБ ОЗУ, стартуют за секунды, потребляют по 150 МБ RAM.
Комментарии (38)
- Речь идёт о запуске 5000 узлов BEAM (Erlang-машин), а не процессов — каждая BEAM может держать миллионы лёгких процессов.
- Сервер с 192 Ampere-ядрами позиционируется как «облачный» или «edge» для телекомов; Hetzner предлагает 80-ядерный Ampere за ~200 $/мес.
- Пользователи сомневаются в полезности без тестов под нагрузкой и обсуждают, как масштабировать память и шину при таком числе ядер.
- Всплыли исторические примеры (Azul для Java) и шутки про «ручное ткачество» Erlang-потоков и «фермерский» байт-код.