0

我对 Linux 上的 C++ 共享库有一个奇怪的问题。

该过程两次加载和卸载我的库(这是设计使然,无法更改)。

  1. 在第一个 dlopen() 期间,我的库中的所有静态成员都以正确的顺序初始化。
  2. 然后,当第一个 dlclose() 被调用时,破坏也按预期进行,顺序与构造相反。
  3. 在第二次 dlopen() 期间,一切正常 - 构造顺序正确,与第一次相同。
  4. 但是在第二个 dlclose() 中,破坏的顺序突然被破坏了——析构函数的调用顺序与它们初始化的顺序相同,如果任何静态对象试图访问一个已经被破坏的对象,它通常会导致 SEGFAULT。
  5. dlopen()/dlclose() 的后续尝试完全重复第 3 步和第 4 步。

我试图用一个最小的例子重现这个问题,但没有成功——使用一个小的假共享库,一切都按预期工作。我的大型图书馆中有一些东西会导致第二个 dlclose() 受到破坏,而且它非常大。

我没有发现对 gcc(尝试 3.2/3.4/4.1.2)和 Linux 发行版(RHEL 4/5,SuSE 10)的依赖。在 Web 中搜索类似案例得到 0 个结果 - 没有类似的。

在实验过程中,我尝试在静态对象构造函数中嵌入一些对 atexit() 的调用,以查看 atexit() 处理程序的顺序是否受到影响,并发现确实如此。步骤 1/2/3 运行良好(dlopen/dlclose/dlopen),然后在第二个 dlclose 上 atexit 注册的处理程序的顺序不正确。

我真的不希望得到答案,但我非常感谢任何有关如何解决问题的建议。

先感谢您,

安德鲁·谢蒂宁

PS 更新 - 我在 GLIBC 的 atexit() 中调试了代码,发现我遇到了一个错误 - 实际上是一个非常简单的错误。它已在 GLIBC 2.4 中修复,我不幸使用 GLIBC 2.3.4

4

2 回答 2

3

这是 GLIBC 2.3.x 中的一个错误,已在 GLIBC 2.4 中修复。

该错误是在非常特定的条件下触发的 - 当一个进程多次打开和关闭具有不同目标文件中的大量静态变量的 C++ 库时。

atexit() 条目被组织在一个由 32 个处理程序指针组成的单链表中,并且 atexit() 中的旧代码将新的处理程序插入到单链表中的错误页面中,从而破坏了 atexit() 调用终结的合同处理程序按照注册的相反顺序进行。

于 2011-11-15T08:53:15.190 回答
0

我不相信您可以通过任何想象来依赖静态 ctor/dtor 顺序。你只是没有得到任何保证。

我希望看到每个只调用一次的 setup 和 teardown 函数。确保你这样做一次是你的强制执行。

于 2011-11-08T23:38:28.583 回答