Хабрахабр

Переход на Boost-1.65.1 и баги, которые всплыли

В прошлом году(уже почти целый год прошел) мы все–таки перешли на новую версию Boost-1.65.1, и под капотом вы найдете тройку багов boost-а, с которыми мы столкнулись. Еще важно упомянуть, что до этого у нас в ПО использовался boost -1.62.1, поскольку какие-то баги появились в boost ранее версии 1.65.1

Также команда интеграции ответственна за устранение всех проблем, которые при этом возникают, естественно при содействии мейнтейнеров компонентов, если это необходимо. В нашем проекте есть специальная команда интеграции, основной задачей которой является миграция всего софта на новую версию библиотек, Visual Studio, новые версии компонентов низкого уровня (базовые, от которых зависят большинство других компонентов) и т.п. Итак, баги, которые особенно запомнились мне.

Баг в boost::filesystem

Этот баг всплыл достаточно быстро. Тесты начали падать с “Access violation” при поиске полного пути к задаваемому имени файла. В функции делался вызов boost::filesystem::exist, и программа крашилась. Запустив еще несколько тестов, было замечено еще несколько аналогичных случаев, при этом во всех случаях вызов boost::filesystem::exist делался для глобальных переменных. Видимо, что-то поменялось во времени жизни переменных boost-та. Тикет для обнаруженного бага очень легко гуглится тикет бага в boost::filesystem::exist

64. Оказалось, что этот баг затесался в boost, начиная с версии 1. В 1. На самом деле проблема была в вызове make_permissions (используется в filesystem::exist). Поэтому попытка доступа к несозданной переменной бросает исключение. 64 имплементация make_permissions была изменена, и теперь использовала глобальные переменные, а это значит, что когда делается попытка вызова filesystem::exist при инициализации глобальной переменной или объекта, глобальные переменные, используемые в make_permissions, могут быть еще не проинициализированы.

Обходной путь

Для тестов, где глобальные переменные использовались только единожды, были перенесены в соответствующие тесты и стали локальными переменными. Даже и не спрашивайте, почему это не было сделано раньше, я не мейнтейнер этого кода.

В остальных случаях использовались синглтоны.

Баг в boost::python

В тестах, использующих boost::python, была обнаружена странная вещь. При выполнении тривиального вызова eval() для литерала (например, «40+2») все норм. А если переменные определить, а потом использовать в выражениях, то получаем сообщение о том, что в вычислениях используются неопределенные переменные(ERROR: [name] not defined). Для решения этой проблемы я потратила уже больше времени. Я не смогла найти тикет этой проблемы в баг трекере boost-а, поэтому пришлось попросить помощи команды этого компонента. Информация о баге была оперативно найдена на github-е.

Пожелав Good luck в поиске фикса без перекомпиляции исходников либы, команда откланялась 🙂 Так случилось, что в имплементации eval объекты global и local не использовались.

Обходной путь

Но тут я вспомнила про release notes для boost-1.65.1 и там точно что-то было для boost::python.

Баг был допущен при добавлении новой имплементации eval c поддержкой char const * аргумента, которая теперь вызывается в старой имплементации eval со string аргументом(Особо внимательные могли заметить вызов этой функции в коде по github-овской ссылке). Ура, выход есть! И новая функция, как ожидалась, работает.

boost::numpy

Это самая нелюбимая моя часть. boost::python::numeric был удален и теперь как альтернатива появился boost::python::numpy. Но код, использовавший numeric, пришлось изрядно переделать, поскольку дело не только в переименовании неймспейсов, но и в имплементации объектов.

Помимо этого, в хедере boost-та была дезинформация, которая ввела меня в заблуждение.
Согласно комментарию в исходнике, вызов import_array() уже делается в numpy::initialize():

namespace boost { namespace python { namespace numpy { /** * @brief Initialize the Numpy C-API * * This must be called before using anything in boost.numpy; * It should probably be the first line inside BOOST_PYTHON_MODULE. * * @internal This just calls the Numpy C-API functions "import_array()" * and "import_ufunc()", and then calls * dtype::register_scalar_converters(). */
BOOST_NUMPY_DECL void initialize(bool register_scalar_converters=true); }}} // namespace boost::python::numpy

Но на деле, как оказалось, import_array() необходим.

Поэтому проблемы выявлялись только при тестировании соответствующего компонента. К тому же, были проблемы с тестированием изменений, поскольку куски кода с numpy (ранее с boost::python::numeric) вообще не были покрыты тестами, а сам код использовался еще и в другом компоненте. Ух и наслушалась я от них о том, что сломала их код. Команда интеграции не обязана писать тесты для компонент, и данная ситуация была упущением самой команды. Однако обидка осталась (при следующей миграции, команда не хотела давать права доступа к своему компоненту моему коллеге, упоминая, что в прошлый раз, мы сломали им код. Но после того, как команда поворчала, они наконец-то покрыли свой код тестами. Саша, сорян! Но после трех дней переговоров они сдались).

Заключение

После проделанной работы могу отметить плюсы для себя, поскольку boost до этого использовала не очень часто(в основном std), поэтому из миграции можно подчеркнуть много нового. Забавно, но факт, после такого почему-то вы по дефолту становитесь для многих коллег “экспертом boost”, и, смиритесь, вам будут задавать вопросы по нему еще некоторое время.

И мы тоже не остались в стороне. Кстати последние годы многие компании начали активно избавляться от boost и заменять по возможности std библиотекой, либо чем-то еще в случае отсутствия каких-то возможностей в стандартной библиотеке. Процесс запущен, но не завершен, еще много работы.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть