Вызов dlclose () из кода, загруженного соответствующей dlopen (), нормально? - PullRequest
0 голосов
/ 09 июля 2020

Вопрос такой же, как в заголовке, и ниже приводится предыстория:

На Linux я пытаюсь использовать dlopen () et c для создания инфраструктуры плагинов C ++ .so, которая имеет минималистичный и чистый интерфейс. Это означает:

  1. Загрузка плагина и создание одноэлементного объекта (C ++) из плагина просто включает в себя вызов функции makePluginObject() с путем к загружаемому файлу .so и возвращением указателя на предмет. Под капотом эта функция вызывает dlopen (), за которым следует фактическое размещение и построение объекта. Объект относится к классу C ++, реализация которого находится в .so.
  2. Позже пользователь может просто удалить (вызывая dtor) указатель, чтобы выполнить всю необходимую очистку, включая dlclose (), что выполняется с помощью доктор. Это будет реализовано путем вызова dlclose () в dtor объекта. (Под капотом дескриптор из dlopen () был передан объекту во время makePluginObject().) Важно отметить, что пользователь не может явно вызвать дополнительную функцию отключения / отключения.

Выше design, вероятно, означает, что код, вызывающий dlclose (), находится в расширяемом .so. Ключевой вопрос таков: нормально ли код вызывать dlclose () сам по себе? Мне интересно, потому что наивная реализация dlclose () отключает отображение из памяти кода, который все еще выполняется во время уничтожения объекта.

Важно, чтобы пользовательский интерфейс оставался таким простым. Пользователю просто нужно вызвать makePluginObject() и удалить полученный указатель, когда он закончит. Если введена функция разрыва, которую пользователь должен явно вызвать после удаления объекта, тогда интерфейс будет намного тяжелее, и нагрузка на пользователя будет намного больше. Я знаю, что делать, если разрешена явная функция разрыва, и этот вопрос не об этом варианте использования.

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

1 Ответ

1 голос
/ 11 июля 2020

Да, вызов dlclose из библиотечной функции приведет к ошибке segfault по указанным вами причинам:

$ cat main.c
#include <dlfcn.h>
int main() {
  void *h = dlopen("./liblib.so", RTLD_LAZY | RTLD_GLOBAL);
  int (*foo)(void *) = dlsym(h, "foo");
  foo(h);
  return 0;
}
[y.gribov@link ~]$ cat lib.c
#include <dlfcn.h>
#include <stdio.h>
int foo(void *h) {
  printf("Before dlclose\n");
  dlclose(h);
  printf("After dlclose\n");
  return 10;
}
$ gcc main.c -ldl
$ gcc -o liblib.so lib.c -shared -fPIC -ldl
$ ./a.out
Before dlcose
Segmentation fault

Непонятно, почему это работает в вашем конкретном случае (ваша библиотека может экспортировать символ GNU_UNIQUE , библиотеку можно dlopen редактировать дважды, и т.д. c.).

...