【问题标题】:Calling dlsym() with a NULL handle doesn't return NULL, but rather returns a random function使用 NULL 句柄调用 dlsym() 不会返回 NULL,而是返回一个随机函数
【发布时间】:2019-11-21 10:19:49
【问题描述】:

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

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() 的指针。

【问题讨论】:

  • 看起来你的实现使用了#define RTLD_DEFAULT ((void*)0),所以你的空指针确实被解释为“无论你先找到哪个”。
  • 养成一个好习惯:每当你调用某个 API 函数(如 dlopen)时,它的返回值清楚地表明它是否失败,请务必检查它并尽快采取适当的行动,而不是依赖在其他地方可以安全使用的值。获得宗教信仰是值得的。它不仅可以使您免于这种“陷阱”情况(可能不会在测试中发现),而且可以让追随您的人更清楚应该发生的事情。
  • @Joe 从现在开始我一定会记住这一点!

标签: c++ c linux dlopen dlsym


【解决方案1】:

我的问题是,当您将 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 中保留,但在其他实现中不一定如此。

在传递给dlsym 之前,您应该检查dlopen 不返回null(或检查dlerror 确实返回null)。

【讨论】:

  • 注意:RTLD_DEFAULT 是为一些(大多数)其他 POSIX C 库(如 FreeBSD 或 macOS 的库)定义的,但它不等于 NULL。因此最好使用RTLD_DEFAULT 而不是NULL
【解决方案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 标志动态加载的共享对象中的符号。

【讨论】:

  • 感谢您回答我的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-23
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多