是否可以在任何地方替换全局“operator new()”?

Posted

技术标签:

【中文标题】是否可以在任何地方替换全局“operator new()”?【英文标题】:Is it possible to replace the global "operator new()" everywhere? 【发布时间】:2010-01-20 19:54:38 【问题描述】:

我想替换全局的operator new()operator delete()(以及它们的所有变体)来做一些内存管理技巧。我希望我的应用程序中的所有代码都使用自定义运算符(包括我自己的 DLL 和第三方 DLL 中的代码)。我已经阅读了链接器将选择链接时看到的第一个定义的内容(例如,如果首先链接包含您的自定义 operator new() 的库,它将“击败”与 CRT 的链接)。有没有办法保证这会发生?这有什么规则,因为这确实是一个多重定义的符号(例如,void* operator new(size_t size) 在全局命名空间中有两个定义)?

可能与 CRT 静态链接的第三方 DLL 怎么样?即使它们与 CRT 动态链接,是否有某种方法可以让它们与 my operator new() 链接?

【问题讨论】:

这充满了危险。您确定要执行此操作(y/N)吗? > DLL 是二进制文件,因此在您获取它们时它们已经被编译和链接。 很公平。我之所以问,是因为如果您的下一个 *** 问题是“如何在非常重要的生产系统上恢复数据?”,我会感到难过。 ;) 在类 Unix 平台上这通常是可能的,但 Window 的动态库模型不同。在 Unix 上,加载时链接通常符合 C++ 翻译阶段第 9 阶段的 C++ 要求,其中包括链接替换 ​​operator newoperator delete。 Windows 的加载时链接实现不符合第 9 阶段,通常无法替换。 【参考方案1】:

C++ 标准明确允许您编写自己的全局运算符 new 和 delete(以及数组变体)。链接器必须让它工作,尽管具体如何由实现者决定(例如,当且仅当一个东西不存在时,像弱外部元素这样的东西有助于提供一些东西)。

就 DLL 而言,它会很棘手:如果没有大量额外的工作,静态链接的 DLL 显然不会使用您的代码。静态链接意味着它已经将库代码的副本复制到 DLL 中,并且 DLL 中使用它的任何代码都具有已经编码的该代码的地址。为了解决这个问题,您必须弄清楚 new 的代码在 DLL 中的位置,并动态修补所有调用它的代码来调用您的代码)。

如果 DLL 动态链接到标准库,它只会稍微容易一些——导入表仍然会编码 DLL 的名称以及该 DLL 中提供所需内容的函数。这可以解决(例如,使用 Microsoft 的 Detours library 之类的东西),但这有点不重要(尽管肯定比 DLL 静态链接标准库时更容易)。

【讨论】:

【参考方案2】:

编辑:重新阅读问题后,我意识到您的重点是第三方组件。所以在这种情况下,答案是否定的。涉及的变量太多了。


(指在您自己的代码中替换“新”)简短的回答是肯定的。这是进行自己的内存管理的系统中的常见技巧。正如您可能已经猜到的那样,正确处理是一件非常棘手的事情,如果您不小心,很容易在您的脸上炸毁,但它肯定是合理的并且被许多软件使用。 (我记得阅读过一些在 Doom 3 SDK 中执行此操作的代码,例如)

至于在第 3 方 DLL 中替换 new 和 delete,这不会发生(至少不安全)。一方面,你怎么知道他们甚至使用 new 和 delete?更不用说他们可能正在做他们自己的这种技术的变体,并依靠它的一些副作用来正常运行。即使你现在让它工作,你怎么知道该组件的某些未来版本不会破坏它?您可以随意使用自己的内存,但为了您和您的用户的理智,请不要尝试对其他二进制文件的内存进行微观管理。

【讨论】:

以上是关于是否可以在任何地方替换全局“operator new()”?的主要内容,如果未能解决你的问题,请参考以下文章

Android:定义一次视图及其子项,并在任何地方重用它

c#在任何地方检测鼠标点击(表格内外)

在任何地方保留任何托管对象是一个坏主意,这是真的吗?

函数进阶

Python list += iterable 的行为是不是记录在任何地方?

java.util.Observable 是不是在任何地方使用?