【问题标题】:C++ test if two DLLs share the same heapC++ 测试两个 DLL 是否共享同一个堆
【发布时间】:2022-10-22 00:21:29
【问题描述】:

众所周知,堆内存的释放必须使用与分配它的分配器相同的分配器。这是在跨 DLL 边界交换堆分配对象时要考虑的事情。

一种解决方案是为每个对象提供一个析构函数,就像在 C API 中一样:如果 DLL 允许创建对象 A,它必须提供一个函数 A_free 或类似的东西1.

另一个相关的解决方案是将所有分配包装到 shared_ptr 中,因为它们存储了指向释放器的链接2.

另一种解决方案是将顶级分配器“注入”到所有加载的 DLL 中(递归地)3.

另一种解决方案是不交换堆分配的对象,而是使用某种协议4.

另一个解决方案是绝对确保 DLL 将共享相同的堆,如果它们共享兼容的编译选项(编译器、标志、运行时等),这应该(将会?)发生56. 这似乎很难保证,特别是如果一个人想使用包管理器而不是一次构建所有东西。

有没有办法在运行时检查多个 DLL 之间的堆实际上是否相同,最好是跨平台的方式?

为了可靠性和易于调试,这似乎比希望应用程序立即崩溃而不是默默地破坏东西要好。

【问题讨论】:

  • 您的解决方案#2根本没有解决方案。 shared_ptr 没有单一的二进制兼容定义。
  • 是的,我知道在 DLL 边界需要考虑两个要点:ABI 兼容性和“堆共享安全”。我的理解是具有“堆共享安全”意味着具有 ABI 兼容性,但倒数是错误的,您确认吗?
  • 不,一点也不,你错过了对单一定义规则的遵守。您可以让两个 C++ 编译器共享相同的分配器(可能由 C 库提供),但使用不兼容的 C++ 标准库。更糟糕的是,std::shared_ptr 不是标准布局类,因此不同的 C++ 编译器看到相同的头文件会产生不同的二进制布局。

标签: c++ memory-management dll shared-libraries heap-memory


【解决方案1】:

我认为这里最大的问题是您对“堆”的定义。假设有一个唯一的定义。

问题是Windows有HeapAlloc,而C++通常使用“堆”作为::operator new分配的内存。这两个可以是相同的、不同的、子集或部分重叠。

对于两个 DLL,它们都可以用 C++ 编写并使用::operator new,但它们都可以链接自己的独特版本。因此,上一段中的观察可能有多个答案。

现在让我们假设一个示例,一个 DLL 将::operator new 直接转发到HeapAlloc,但另一个在调用HeapAlloc 之前计算分配。显然这两者不能正式混合,因为第二个分配器保留的计数是错误的。但是代码非常简单,以至于news 都可能是内联的。因此,在装配级别,您只需致电HeapAlloc

即使您将动态反汇编代码(!),您也无法在运行时检测到这一点 - 内联的计数器增量指令与周围的代码无法区分。

【讨论】:

  • 它们甚至都可以直接调用HeapAlloc(),但使用不同的堆句柄。
猜你喜欢
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2010-11-19
相关资源
最近更新 更多