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.
Итог
Ни один компонент по отдельности не «сломан», но их комбинация приводит к крашу компилятора на валидном коде.
Комментарии (32)
- Участники сетуют, что C++ стремительно усложняется ради «чуть более удобного» синтаксиса.
- @twoodfin возражает: главная цель — не синтаксис, а упрощение создания абстракций.
- @immibis сравнивает рост сложности C++ с переходом от ассемблера к C: каждая новая фича множит сложность, но и выгоду.
- @mgaunard предупреждает: даже минорные обновления компиляторов могут тихо ломать код, поэтому апгрейд требует тщательного тестирования.
Compiling a Lisp: Lambda lifting
Переписал Ghuloum-туториал на Python (~300 строк). Убрал читалку S-выражений и бинарный код — теперь текстовая ассемблерная печать.
Lambda-lifting требует:
- знать связанные переменные;
- собирать свободные переменные лямбд;
- накапливать создаваемые
code
-объекты.
Связывают let
и lambda
; для них обновляем окружение.
Lifter
class LambdaConverter:
def __init__(self):
self.labels = {}
def convert(self, expr, bound, free):
match expr:
case int() | Char() | bool():
return expr
case str() if expr in bound or expr in BUILTINS:
return expr
case str():
free.add(expr)
return expr
case ["if", t, c, a]:
return ["if",
self.convert(t, bound, free),
self.convert(c, bound, free),
self.convert(a, bound, free)]
lift_lambdas
запускает обход и возвращает (labels …)
.
Lambda
Лямбда:
- связывает параметры;
- выделяет код;
- захватывает внешнее окружение.
Пример:
(lambda () x) ; x свободна
превращается в
(labels ((f0 (code () (x) x)))
(closure f0 x))
Даже если x
связан снаружи, внутри лямбды он считается свободным.
Комментарии (15)
- Участники рекомендуют три современные книги по компиляторам, вдохновлённые статьёй Ghuloum: «Writing a C Compiler» (Sandler), «Essentials of Compilation» на Racket и Python (Siek).
- Обсуждали «lambda lifting»: преобразование, выносящее замыкания наверх, уменьшая их размер вплоть до полного исчезновения.
- Уточнили, что «lambda lifting» в статье связан с разделом 3.11 о сложных константах в Scheme.
- Разбирали, почему современный ИИ использует Python, а не Lisp: удобство как «клея» для C++/CUDA, упадок доли рынка Lisp и смена парадигмы ИИ.
Gleam v1.12
-
Исправления
- Уточнено сообщение об ошибке с некорректной терминологией. (Louis Pilfold)
- JS: устранён сбой при использовании echo в модуле с функцией process. (Peter Saxton)
- Форматер: не переносит комментарий перед assert за него; корректно форматирует сообщения после echo/panic/todo/assert/let assert с комментарием перед ними; компилятор не генерирует неверный код для assert с пайпами на JS. (Giacomo Cavalieri)
-
Форматирование битовых массивов
- Трейлинг-Запятая управляет разбиением: с запятой — много строк; без — в одну строку.
- Если несколько сегментов на строке и убрана завершающая запятая, форматер сохраняет сегменты по одному на строку. (Giacomo Cavalieri)
-
Компилятор и генерация кода
- echo поддерживает пользовательское сообщение: echo 11 as "lucky number" печатает контекст и значение в stderr. (Giacomo Cavalieri)
- В сгенерированном JS doc-комментарии превращаются в JSDoc. (Giacomo Cavalieri)
- Уменьшен размер кода case на JS. (Surya Rose)
- Удаление неиспользуемого кода на этапе генерации (usage-based DCE). (Louis Pilfold)
- Улучшена поддержка echo для списков символов, ошибок и циклических ссылок JS. (Louis Pilfold)
- Улучшен внешний вид ошибок и предупреждений: контекстные метки выделяются иначе, чем источник проблемы. (Giacomo Cavalieri)
- Подсказка при импорте с точкой вместо слеша, с примерами корректного синтаксиса. (Zij-IT)
- Предупреждение при затенении импортированного имени верхнеуровневой константой/функцией. (Aayush Tripathi)
- Улучшено сообщение об неизвестной переменной, если, вероятно, имелась в виду проигнорированная (_x → x), с подсказкой. (Giacomo Cavalieri)
- Оптимизирован матчинг-паттернов на JS.
Комментарии (80)
- Обсуждение посвящено релизу Gleam: многие хвалят дизайн языка, читаемость, статическую типизацию и паттерн-матчинг; приводят пример кода и делятся позитивным опытом использования в проектах.
- Есть ссылки на пост о версии 1.12.0 и доклад на YouTube; некоторые ждут дальнейшего созревания экосистемы и возможности шаринга кода между фронтендом и бэкендом.
- Критика: отсутствие интерфейсов/тайпклассов и оператора композиции; кому-то синтаксис и «Error -> Error» кажутся неэлегантными; snake_case непривычен после TypeScript.
- В ответ отмечают осознанную простоту языка и официальную позицию Gleam по отказу от тайпклассов.
- Существенная часть треда уходит в спор о «идеологичном» футере сайта (инклюзивность, антинацистская позиция, права транс-людей): часть считает это лишним, другие — важным для безопасности и качества сообщества.
- Подчеркивается, что Gleam — это не только язык, но и сообщество с явным кодексом поведения; отсутствие позиции тоже является позицией.
- Некоторые участники призывают вернуться к техническим темам релиза, чтобы не повторять одни и те же дискуссии.
Комментарии (54)
A really good accompaniment to this is Carruth's "C++, bounds checking, performance, and compilers" [1]:> ... strong belief that bounds checks couldn’t realistically be made cheap enough to enable by default. However, so far they are looking very affordable. From the above post,