Что происходит с потоком, порожденным общей библиотекой, при dlclose - PullRequest
0 голосов
/ 03 июля 2018

Это сценарий:

У меня есть приложение (main.exe), которое динамически загружает библиотеку libA.so с помощью dlopen (). libA.so зависит от другой библиотеки libB.so.

Теперь в libB.so есть конструктор, который порождает поток (в отключенном состоянии) и блокирует чтение из именованного канала.

Что происходит с потоком, когда libA.so выгружается с помощью dlclose () - (я предполагаю, что это также выгружает libB.so)?.

Я получаю ошибку сегментации в потоке после dlclose (libA.so).

Псевдокод:

main.c (main.exe):

handle = dlopen(libA.so)
// function calls
dlclose(handle)

libA.so зависит от libB.so

b.c (libB.so):

__attribute_constructor__void start() {
    pthread_create(ThreadFunction)

void ThreadFunction() {
    while(1) {
    fd = open("path_to_pipe", READONLY)
    read(fd, buffer, size)
    //Process the content
    }

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Поздравляем - вы вновь обнаружили, что не-nop dlclose реализация принципиально небезопасна. Язык C не предусматривает код или данные псевдостатического хранилища, время жизни которых отличается от всего времени жизни программы, и в целом код библиотеки не может быть безопасно удален, так как ссылки на него могут быть разными слил и все еще быть доступным. Вы действительно нашли исключительно хороший пример; Обычные реализации пытаются перехватить и «исправить» утечки с помощью atexit и т. д., запустив обработчики во время dlclose, но, похоже, нет никакого способа перехватить и исправить оставленный поток.

В качестве обходного пути есть специальный флаг ELF, который вы можете установить, передавая -Wl,-z,nodelete при связывании общей библиотеки libB.so (или libA.so, если это более удобно, например, если вы не контролируете, как libB.so связан), что предотвратит его выгрузку dlclose. К сожалению, этот дизайн задом наперед. Выгрузка принципиально небезопасна, если библиотека специально не написана для защиты от выгрузки, поэтому по умолчанию должен быть «nodelete» с явной опцией, необходимой для возможности выгрузки. К сожалению, мало шансов, что это когда-нибудь будет исправлено.

Еще один способ предотвратить выгрузку - вызвать на конструкторе вызов dlopen для утечки ссылки, чтобы счетчик ссылок всегда был положительным и dlclose ничего не делал.

0 голосов
/ 03 июля 2018

Выгрузка разделяемой библиотеки, которая все еще используется, является неопределенным поведением. Вызов dlclose() для дескриптора является объявлением о том, что ни функции, ни объекты данных, предоставленные через этот дескриптор, по-прежнему не требуются.

У dlclose() нет возможности проверить этот факт. Если в загружаемом модуле все еще есть указатель на функцию или объект данных, эти указатели становятся недействительными и могут не использоваться. Если есть указатель на загруженную функцию в стеке вызовов любого потока - что будет в случае, если поток ожидает дескриптор файла - тогда этот поток может не вернуться в этот кадр вызова. (Longjmp к предыдущему кадру может сработать, если стек можно разматывать без ссылки на выгруженный модуль. Это, вероятно, будет работать в C, но создание исключения C ++ для выхода из незагруженной функции, скорее всего, завершится неудачей.

...