Архивный материал Mozilla (май 2021 г.). Указанные версии, результаты и планы относятся к публикации источника. Первоисточник.
Улучшение устойчивости Firefox на Linux
Примерно год назад в Mozilla мы начали работу по улучшению устойчивости Firefox на Linux. Это начинание быстро стало примером успешного взаимодействия между проектами с открытым исходным кодом.
Каждый раз, когда Firefox падает, пользователь может отправить нам отчет о падении, который мы используем для анализа проблемы и, надеемся, исправления её: Этот отчет содержит, среди прочего, minidump — небольшой снимок памяти процесса на момент падения. Он включает содержимое регистров процессора, а также данные из стэков всех потоков. Вот как это обычно выглядит:
Если вы знакомы с core dump, то minidump по сути является их уменьшенной версией. Формат minidump был изначально разработан в Microsoft и в Windows есть встроенный механизм записи minidump. На Linux для этой задачи мы используем Breakpad. Breakpad возник в Google для их программ (Picasa, Google Earth и т. п.), но мы форкнули его, значительно модифицировали под наши нужды и недавно частично переписали на Rust.
После того как пользователь отправляет отчет о падении, на сервере у нас есть компонент — Socorro — который обрабатывает отчет и извлекает из minidump стек вызовов. Отчеты затем группируются на основе имени верхней функции в стеке падающего потока. Когда обнаруживается новая ошибка, мы заводим баг и начинаем работать над ним. Ниже приведена иллюстрация того, как группируются падения:
Чтобы извлечь содержательный стек вызовов из minidump, нужны ещё две вещи: информация для развёртывания стека (unwinding information) и символы. Информация для развёртывания — это набор инструкций, описывающих, как найти разные фреймы в стеке, зная указатель инструкции. Информация о символах содержит имена функций, соответствующие диапазону адресов, а также исходные файлы и номера строк, которым соответствует та или иная инструкция.
В обычных сборках Firefox мы извлекаем эту информацию из файлов сборки и сохраняем её в символьные файлы в формате, принятом Breakpad. Оснащённый этой информацией, Socorro может сформировать человекочитаемый стек вызовов. Вся схема выглядит так:
Вот пример корректного стека вызовов:
Если у Socorro нет доступа к соответствующим символьным файлам для падения, полученный стек содержит только адреса и малоинформативен:
На Linux всё работает иначе, чем на других платформах: большинство наших пользователей не устанавливают сборки от нас напрямую, они пользуются версией Firefox, упакованной для их любимого дистрибутива. Это создавало серьёзную проблему при анализе стабильности на Linux: для большинства отчетов о падении мы не могли получить качественные стеки вызовов, потому что у нас не было необходимой информации о символах. Отчеты присылали сборки Firefox, сделанные не нами. В довершение ко всему, Firefox зависит от множества сторонних пакетов (таких как GTK, Mesa, FFmpeg, SQLite и др.). Мы не получали хорошие стеки, если падение происходило в одном из этих пакетов, а не в самом Firefox, потому что символов для них у нас тоже не было.
Чтобы решить эту проблему, мы начали собирать информацию отладки (debug information) для сборок Firefox и их зависимостей из репозиториев пакетов нескольких дистрибутивов: Arch, Debian, Fedora, OpenSUSE и Ubuntu. Поскольку каждый дистрибутив делает это немного по‑своему, нам пришлось написать скрипты для конкретных дистрибутивов, которые проходят по списку пакетов в их репозиториях и находят соответствующую информацию отладки (скрипты доступны здесь). Эти данные затем передаются инструменту, который извлекает символьные файлы из информации отладки и загружает их на наш символ-сервер.
Имея теперь эту информацию, мы смогли проанализировать более 99% отчетов о падениях, которые приходили от пользователей Linux, по сравнению с менее чем 20% ранее. Вот пример высококачественного трассирования, извлечённого из версии Firefox, упакованной дистрибутивом. Мы не собирали ни одной из задействованных библиотек сами, но имена функций присутствуют, как и файлы и номера строк затронутого кода:
Значение этого трудно переоценить: пользователи Linux обычно более технически подкованы и с большей вероятностью помогут нам решить проблемы, поэтому все эти отчеты стали кладезем для улучшения стабильности и для других операционных систем (Windows, Mac, Android и т. д.). В частности, мы часто первыми обнаруживали баги Fission именно на Linux.
Первый эффект от этой новой возможности инспекции падений на Linux — существенное ускорение нашего времени реакции на проблемы, специфичные для Linux, и часто возможность выявлять проблемы в Nightly и Beta версиях Firefox до того, как они дошли до пользователей релизной ветки.
Мы также могли быстро выявлять проблемы в передовых компонентах, таких как WebRender, WebGPU, Wayland и VA-API для аппаратного ускорения видео; нередко предоставляя исправление в течение нескольких дней после появления изменения, вызвавшего проблему.
Мы на этом не остановились: теперь мы могли выявлять проблемы и регрессии, специфичные для дистрибутивов. Это позволяло нам уведомлять поддерживающих пакеты мейнтейнеров о проблемах и быстро добиваться их исправления. Например, мы смогли определить специфичную для Debian проблему уже через две недели после того, как она была введена, и сразу же её исправили. Падение было вызвано модификацией, сделанной Debian в одной из зависимостей Firefox, которая могла привести к падению при запуске; если вам интересны детали, это описано в баге 1679430.
Другой хороший пример — Fedora: они использовали собственную систему отчётов о падениях (ABRT) для перехвата падений Firefox в своих сборках, но благодаря нашим улучшениям начали перенаправлять падения Firefox к нам.
Мы также наконец смогли выявлять регрессии и проблемы в наших зависимостях. Это позволяло нам сообщать об ошибках в upstream и иногда вносить исправления, что приносило пользу как нашим пользователям, так и их пользователям.
Например, в какой‑то момент Debian обновил пакет fontconfig, обратно портировав upstream‑фикс утечки памяти. К сожалению, исправление содержало баг, который вызывал падение Firefox и, возможно, другого ПО. Мы обнаружили новое падение всего через шесть дней после того, как изменение попало в исходники Debian, а через пару недель проблема была исправлена и в upstream, и в Debian. Мы также отправляли отчеты и исправления в другие проекты, включая Mesa, GTK, glib, PCSC, SQLite и другие.
Ночные (Nightly) версии Firefox также включают инструмент для обнаружения проблем, чувствительных в плане безопасности: probabilistic heap checker. Этот инструмент случайным образом расширяет несколько выделений памяти, чтобы обнаружить переполнения буфера и обращения к уже освобождённой памяти. Когда он обнаруживает такую проблему, он отправляет нам очень подробный отчет о падении. Учитывая большую базу пользователей Firefox на Linux, это позволило нам выявить некоторые скрытые проблемы в upstream‑проектах и сообщить о них.
Это также выявило некоторые ограничения в инструментах, которые мы используем для анализа падений, поэтому мы решили переписать их на Rust, во многом опираясь на отличные crates, разработанные Sentry. Получившиеся инструменты оказались значительно быстрее старых, использовали долю памяти и давали более точные результаты. Разработка велась в обе стороны: мы внесли улучшения в их crates (и их зависимости), а они расширили свои API, чтобы учесть наши новые случаи использования, и исправили обнаруженные нами проблемы.
Ещё один приятный побочный эффект этой работы — Thunderbird теперь тоже получает преимущества от улучшений, сделанных для Firefox.
Это демонстрирует, что сотрудничество между проектами с открытым исходным кодом не только приносит пользу их пользователям, но в конечном счёте улучшает всю экосистему и более широкое сообщество, которое на неё опирается.
Особая благодарность Calixte Denizet, Nicholas Nethercote, Jan Auer и всем другим, кто внёс свой вклад в это усилие!
Спасибо! Пожалуйста, проверьте вашу почту, чтобы подтвердить подписку. Если вы ранее не подтверждали подписку на рассылку, связанную с Mozilla, возможно, вам потребуется это сделать. Пожалуйста, проверьте входящие или папку со спамом на наличие письма от нас.
