其他分享
首页 > 其他分享> > c – dlclose不会真正卸载共享对象,无论它被调用多少次

c – dlclose不会真正卸载共享对象,无论它被调用多少次

作者:互联网

我的程序使用dlopen加载共享对象,然后使用dlclose卸载它.有时这个共享对象会再次加载.我注意到静态变量没有被重新初始化(这对我的程序来说是至关重要的)所以我在dlclose之后添加了一个测试(dlopen with RTLD_NOLOAD)来查看库是否真的被卸载了.果然,它还在记忆中.

然后我尝试重复调用dlclose直到库真的被卸载,但我得到的是一个无限循环.这是我用来检查库是否已卸载的代码:

dlclose(handles[name]);

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

  dlclose(handle);
} while (true);

我的问题是,在dlclose之后我的共享对象没有被卸载的原因是什么,因为我的dlopen调用是唯一加载它的地方.你能否提出一个行动方案来追查问题的根源?另外,为什么重复调用dlclose没有效果,它们每个都会减少引用计数,不是吗?

编辑:刚刚发现只有当我用gcc编译时才会发生这种情况.有了clang,一切都很好.

解决方法:

POSIX标准实际上不需要dlclose从地址空间卸载库:

Although a dlclose() operation is not required to remove structures
from an address space, neither is an implementation prohibited from
doing so.

资料来源:The Open Group Base Specifications Issue 6

这意味着除了使句柄无效之外,dlclose根本不需要做任何事情.

有时卸载也会被系统延迟,它只是将库标记为“要删除”,并且实际上会在稍后的某个时间执行该操作(为了提高效率,或者因为现在根本无法执行该操作).但是,如果在执行之前再次调用dlopen,则会清除该标志并重新使用仍然加载的库.

在某些情况下,系统肯定知道库中的某些符号仍在使用中,在这种情况下,它不会从地址空间中卸载它以避免悬空指针.在某些情况下,系统并不确定它们是否正在使用中,但它也可能无法确定它们不是,更好的安全而不是遗憾,在这种情况下它永远不会真正从内存中删除该库.

还有其他更加模糊的情况取决于操作系统类型,通常也在版本上.例如.一个常见的Linux问题是如果您创建了一个使用STB_GNU_UNIQUE符号的库,该库被标记为“不可卸载”,因此将永远不会被卸载.请参阅here,here(DF_1_NODELETE表示不可卸载)和here.因此,它还可以取决于编译器生成的符号或符号类型.尝试在库上运行readelf -Ws并查找标记为UNIQUE的对象.

一般来说,你不能真正依赖dlclose来按照你的预期工作.在实践中,我看到它在过去十年中“失败”而不是“成功”(好吧,它从未真正失败过,它通常不会从内存中卸载库;但它按照标准的要求工作).

标签:c-3,dlopen,c,linux,gcc
来源: https://codeday.me/bug/20191006/1861227.html