tgoop.com/gdb_dbg/268
Last Update:
Есть в libc
такая функция dl_iterate_phdr. Она позволяет проитерироваться по всем загруженным so-шкам и на каждой выполнить колбэк, который ей передается в качестве параметра. Удобная, классная штука!
А вот как вы думаете, что будет, если из таких вот колбэков позвать dlopen
: функцию, которая загружает новые so-шки. Т.е. в момент итерации по коллекции сошек добавить туда новые элементы? Понятно, что идея звучит не блестяще, но все-таки: что именно случится? Сегфолт? UB? Зависнет? Какое-нибудь красивое поведение, типа "вернуть на очередной итерации специальное значение, которое обозначает, что коллекция изменилась"? (ага, щас прям, размечтался, ты не в Java)
Вполне допускаю, что может и сегфолтнуться, но вчера отлаживал прекрасный дедлок, который был вызван вот таким кодом. Прекрасно в нем то, дедлокнулся такой код со случайным тредом-доходягой.
Вот представьте, живет и работает себе тред №1, никак с вашим кодом не связанный. В какой-то момент решает помереть, позвав pthread_exit
. Но вот pthread_exit
во время своей работы может попытаться подгрузить библиотечку libgcc_s.so
(нашел время!), конечно же через dlopen
=> dlopen
в свою очередь первым делом захватит лок на загрузку: dl_load_lock
=> а потом, если мы реально смогли загрузить библиотеку, попытаемся добавить результат в список загруженных сошек, мы возьмем еще один лок: dl_load_write_lock
.
А в этот момент тред №2 такой классный шарится по всем сошкам через dl_iterate_phdr
и зовет для каждого из них ваш кастомный колбэк. Конечно же, чтобы пробегать по списку он сначала берет dl_load_write_lock
, иначе вдруг список поменяется? А наш кастомный колбэк зовет dlopen
, который, как мы уже знаем, первым делом возьмет dl_load_lock
. Дедлок!
Понятно, что пример можно было бы намного проще написать: любой другой тред, который пойдет звать dlopen
– наш конкурент. Но от бедных тредов-доходяг я такого не ожидал. А случалось все это на терминации рантайма, где как раз все и умирают (очень интересное состояние рантайма).
Да, кстати, в мане для dl_iterate_phdr
никто не пишет, что из колбэков не стоит звать dlopen
. Но так ведь и над каждой розеткой не пишут, что не стоит в нее пальцы совать.
—
Смешно, что раньше в нашей кодовой базе на вызове dl_iterate_phdr висела кое-что подсказывающая компилятору пометка @Quick
. Потом ее убрали, и проблема начала проявляться. Вопрос веры, получается: пока верили, что вызов быстрый, он и заканчивался быстро, без всяких дедлоков. Стоило усомниться, и вот мы здесь.
#дух_машины
BY Алло, это отладочная?
Share with your friend now:
tgoop.com/gdb_dbg/268