Dlclose на самом деле не выгружает общий объект, независимо от того, сколько раз он вызывается

Моя программа использует dlopen загрузить общий объект и позже dlclose разгрузить его. Иногда этот общий объект загружается еще раз. Я заметил, что статические переменные не инициализируются повторно (что крайне важно для моей программы), поэтому я добавил тест (dlopen с RTLD_NOLOAD) после dlclose чтобы увидеть, действительно ли библиотека выгружена. Конечно же, это было еще в памяти.

Я тогда попробовал позвонить dlclose несколько раз, пока библиотека действительно не выгружена, но я получил бесконечный цикл. Это код, который я использую, чтобы проверить, была ли библиотека выгружена:

dlclose(handles[name]);

do {
void *handle = dlopen(filenames[name], RTLD_NOW | RTLD_NOLOAD);
if (!handle)
break;

dlclose(handle);
} while (true);

Мой вопрос: каковы возможные причины, по которым мой общий объект не выгружается после dlclose, учитывая, что мой dlopen звонки — единственные места, где он загружен. Можете ли вы предложить план действий, чтобы найти источник проблемы? Кроме того, почему повторные звонки dlclose не имеют никакого эффекта, каждый из них уменьшает счетчик ссылок, не так ли?

РЕДАКТИРОВАТЬ: Просто обнаружил, что это происходит только тогда, когда я компилирую с НКУ. С лязг, все просто отлично

10

Решение

Стандарт POSIX на самом деле не требует dlclose когда-либо выгружать библиотеку из адресного пространства:

Хотя операция dlclose () не требуется удалять конструкции
из адресного пространства, ни одна реализация не запрещена
делать это.

Источник: Открытая группа базовых спецификаций, выпуск 6

Это означает что-то иное, чем недействительность ручки, dlclose не требуется ничего делать вообще.

Иногда выгрузка также задерживается системой, она просто помечает библиотеку как «подлежащую удалению» и фактически выполняет эту операцию в более позднее время (для эффективности или потому, что сейчас просто невозможно выполнить эту операцию). Однако, если вы позвоните dlopen еще раз, прежде чем это когда-либо было выполнено, флаг очищается, и все еще загруженная библиотека используется повторно.

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

Существуют и другие неясные случаи, зависящие от типа операционной системы, а также часто от версии. Например. Распространенная проблема Linux — если вы создали библиотеку, которая использует символы STB_GNU_UNIQUE, эта библиотека помечается как «не выгружаемая» и, следовательно, просто никогда не будет выгружена. Увидеть Вот, Вот (DF_1_NODELETE означает не выгружается) и Вот. Так что это также может зависеть от того, какие символы или тип символов генерирует компилятор. Попробуйте запустить readelf -Ws в вашей библиотеке и ищите объекты, помеченные как UNIQUE,

В общем, вы не можете полагаться на dlclose работать, как вы могли ожидать. На практике я видел, как он «проваливался» чаще, чем «преуспевал» за последние десять лет (ну, в действительности, он никогда не сбивался, просто часто не выгружал библиотеку из памяти, но все же работал в соответствии с требованиями стандартов).

12

Другие решения

Это не ответ на все ваши вопросы, но это решение, которое может помочь вам избежать проблем с dlclose, Этот вопрос предлагает подсказку о том, как повлиять на поведение при повторной загрузке разделяемых библиотек: вы можете использовать флаг компилятора -fno-gnu-unique,

Из справочных страниц для gcc / g++:

-FNo-гну-уникальное

В системах с недавним GNU-ассемблером и библиотекой C компилятор C ++ использует привязку «STB_GNU_UNIQUE», чтобы гарантировать уникальность определений статических членов-данных шаблона и статических локальных переменных во встроенных функциях даже при наличии «RTLD_LOCAL»; это необходимо, чтобы избежать проблем с библиотекой, используемой двумя разными подключаемыми модулями «RTLD_LOCAL», в зависимости от определения в одном из них и, следовательно, от несогласия с другим относительно привязки символа. Но это приводит к тому, что «dlclose» игнорируется для затронутых DSO; если ваша программа использует повторную инициализацию DSO с помощью «dlclose» и «dlopen», вы можете использовать -fno-gnu-unique.

Будь то -fno-gnu-unique используется по умолчанию или нет, зависит от того, как был настроен GCC: --disable-gnu-unique-object включает этот флаг по умолчанию, --enable-gnu-unique-object отключает это.

2

Есть много особенностей динамической загрузки библиотеки. Полагаться на ОС для инициализации статических переменных чревато проблемами. Вам гораздо лучше либо вообще избегать этого, либо использовать загрузчик плагинов, который обрабатывает все особые случаи для вас.

Я рекомендую вам проверить гибкие модули. бойкий обеспечивает независимый от платформы способ загрузки динамических библиотек. Вы можете использовать эти обратные вызовы:

Они могут обрабатывать выделение и освобождение любых ресурсов. Вместо того, чтобы полагаться на ОС для надежного распределения статики, вы можете динамически распределять то, что вам нужно.

Все, что вам нужно сделать, это определить эти функции в вашей динамической библиотеке, а затем загрузить и выгрузить их с помощью:

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector