
Инженеры OpenAI рассказали историю, которая звучит как детектив, но с ассемблером и миллионами запросов.
Они нашли баг, который жил в популярной библиотеке libunwind целых 18 лет. Он срабатывал только в микроскопическом окне — буквально одна процессорная инструкция, около 100 пикосекунд (это 0,0000000001 секунды).
На обычной машине такой баг никогда бы не проявился. Но на нагрузке ChatGPT он вызывал больше десятка падений в день. Рассказываю, как его искали.
С чего всё началось
OpenAI использует для поиска по перепискам в ChatGPT инфраструктуру Rockset — C++-поисковый движок, который купили в 2024 году.
И там начали падать процессы.
Причём странно:
- функция возвращалась не туда — иногда по нулевому адресу (NULL)
- иногда указатель стека оказывался смещён на 8 байт
- никаких явных причин не было
Инженеры перебирали гипотезы — и каждая разбивалась о факты. Баг выглядел невозможным.
Как меняли подход
Сначала отлаживали как врач: брали один «труп» (core-дамп) и пытались поставить диагноз по деталям. Это не работало.
Тогда поменяли подход на эпидемиологический — перестали смотреть на единичный случай и посмотрели на всю «популяцию» крашей.
Скрипт для анализа написал… сам ChatGPT. Он скачал и разметил все дампы памяти Rockset за год.
И корреляции проявились мгновенно.
Два бага вместо одного
На чистых данных оказалось, что проблема — не одна, а две независимые:
- Тихий аппаратный сбой. Процессор на одном хосте Azure просто неправильно считал.
- Гонка потоков (race condition) в libunwind. Вот это оказалось главным.
Что за баг и как он работал
libunwind — это библиотека, которая «раскручивает» стек, когда в C++ происходит исключение. Она меняет указатель стека — и ровно на одну инструкцию структура с адресом возврата оказывается за пределами защищённой зоны.
Если именно в этот момент прилетает системный сигнал, ядро затирает эту память — и адрес возврата превращается в NULL. Программа падает.
Почему он не вылезал 18 лет
Код появился ещё в 2007–2008 годах в первой версии libunwind для x86_64. И всё это время он спокойно работал.
Почему же он проявился у OpenAI?
- Огромная нагрузка. Rockset кидает очень много исключений.
- Частые сигналы. Очень часто шлёт системные сигналы.
- Недавнее изменение. Обработчик сигнала стал занимать больше стека.
Только на пересечении этих трёх факторов баг пересёк порог видимости.
Как починили
В качестве лечения OpenAI:
- Пересела с GNU libunwind на механизм раскрутки из libgcc
- Отправила в libunwind воспроизводимый пример и код исправления
Что это значит и какой вывод
Главный вывод инженеры OpenAI делают не про ассемблер и не про сигналы. А про подход к отладке.
Пока два разных явления смешивали в одно, найти объяснение было невозможно. Как только данные стали чище — отладка стала простой.
Если коротко
OpenAI нашла баг, который 18 лет жил в библиотеке для раскрутки стека. Он проявлялся только на масштабах ChatGPT — в окне шириной в одну инструкцию (100 пикосекунд).
История показывает, что:
- «Невозможные» баги часто оказываются реальными. Просто они проявляются только на очень высоких нагрузках.
- Качественные данные важнее гениальных догадок. Когда смешаны два разных явления — ничего не понятно. Когда данные разделены — всё становится очевидным.
- Даже старый, проверенный код может содержать ошибки. Баг был написан 18 лет назад и всё это время просто… ждал.
И да, для анализа использовали самого ChatGPT. Ирония судьбы — ИИ помог найти баг, который мешал работать ИИ.
Читайте также: Новости кибербезопасности







