Вызов dlsym () с дескриптором NULL не возвращает NULL, а возвращает случайную функцию - PullRequest
4 голосов
/ 11 июля 2019

Мой заголовок может быть неясным, поэтому позвольте мне объяснить. У меня есть кусок кода, который выглядит так:

void* pluginFile = dlopen(fileName, RTLD_LAZY);
auto function = dlsym(pluginFile, "ExpectedFunction");

Это прекрасно работает, если dlopen возвращает правильный файл. Моя проблема в том, что dlopen не находит файл и возвращает NULL. В настоящее время происходит то, что этот вызов сделан:

dlsym(0x0, "ExpectedFunction");

Проблема в том, что в моем проекте возвращается случайная функция с именем ExpectedFunction. Я думал, что произойдет, что dlsym вернет NULL, поскольку переданный дескриптор NULL. Я не могу найти ожидаемое поведение для такого варианта использования в Интернете.

Мой вопрос: что должно произойти, если вы передадите дескриптор NULL на dlsym? Будет ли он просто возвращать NULL или будет интерпретировать его как дескриптор в местоположении 0x0? Если целочисленное поведение является последним, тогда я просто добавлю проверку, чтобы убедиться, что dlopen suceeded. Если нет, я хотел бы знать, почему он случайным образом возвращает функцию с тем же именем из другой библиотеки, если дескриптор равен NULL.

В настоящее время я использую 10 общих библиотек, в которых есть функция ExpectedFunction(). Однако, если мы вызовем dlopen с именем файла разделяемой библиотеки, которая не существует, она вернет NULL. Затем dlsym вернет указатель на ExpectedFunction() последней загруженной библиотеки.

Ответы [ 2 ]

6 голосов
/ 11 июля 2019

Мой вопрос: что должно произойти, если вы передадите дескриптор NULL в dlsym?

В спецификации сказано:

Если дескриптор нессылка на действительный объект, открытый с помощью dlopen () ... dlsym () должна вернуть NULL.

Однако , существуют некоторые зарезервированные значения дескриптора, которые имеют специальное поведение.Если вы передадите такой зарезервированный дескриптор, то поведение будет другим.Точные значения не указываются POSIX, но, например, в glibc:

# define RTLD_NEXT        ((void *) -1l)
# define RTLD_DEFAULT        ((void *) 0)

(void *) 0 является нулевым, и поэтому вы случайно передали RTLD_DEFAULT в dlsym.Об этом в спецификации сказано:

RTLD_DEFAULT

Поиск символа происходит в обычной глобальной области видимости;то есть поиск символа с использованием этого дескриптора найдет то же определение, что и прямое использование этого символа в программном коде.

Итак, в заключение, что должно произойти, зависит от того,NULL является зарезервированным значением или нет.Он зарезервирован в glibc, и вполне вероятно в других реализациях.

Вы должны проверить, что dlopen не возвращает ноль (или проверить, что dlerror возвращает ноль), прежде чем перейти к dlsym.

2 голосов
/ 11 июля 2019

Из dlfcn.h в Ubuntu Linux:

/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT
   the run-time address of the symbol called NAME in the global scope
   is returned.  */
# define RTLD_DEFAULT   ((void *) 0)

и с dlsym man-page:

RTLD_DEFAULT

Найти первое вхождение нужного символа, используя порядок поиска общих объектов по умолчанию. Поиск будет включать глобальные символы в исполняемом файле и его зависимостях, а также символы в общих объектах, которые были динамически загружены с флагом RTLD_GLOBAL.

...