使用NULL句柄调用dlsym()不会返回NULL,而是返回一个随机函数

时间:2019-07-11 16:24:07

标签: c++ c linux dlopen dlsym

我的标题可能不清楚,所以请允许我解释一下。我有一段这样的代码:

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

如果dlopen返回正确的文件,则可以正常工作。我的问题是dlopen找不到文件并返回NULL时。当前发生的情况是发出了此呼叫:

dlsym(0x0, "ExpectedFunction");

问题是这会在我的项目中返回一个随机函数,称为ExpectedFunction。我以为会发生这种情况,因为传递的句柄是NULL,dlsym将返回NULL。我无法在线找到这种用例的预期行为。

我的问题是,当您将NULL句柄传递给dlsym时会发生什么?它会简单地返回NULL还是将其解释为位置0x0的句柄?如果是后者的行为,那么我将简单地添加一个检查以确保dlopen suceeded。如果不是,我想知道为什么如果句柄为NULL,它会从另一个库中随机返回一个具有相同名称的函数。

我当前的用例是,我正在加载10个共享库,这些共享库都具有功能ExpectedFunction()。但是,如果我们使用不存在的共享库的文件名调用dlopen,它将返回NULL。然后,dlsym将返回指向最后加载的库的ExpectedFunction()的指针。

2 个答案:

答案 0 :(得分:6)

  

我的问题是,当将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是否返回空值)。

答案 1 :(得分:2)

从Ubuntu Linux上的dlfcn.h

/* 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手册页中的

  

RTLD_DEFAULT

     

使用默认的共享库搜索顺序查找所需符号的首次出现。搜索将包括可执行文件及其依赖项中的全局符号,以及使用RTLD_GLOBAL标志动态加载的共享对象中的符号。