0

在我的应用程序中,我有很多空指针(这是由于历史原因,应用程序最初是用纯 C 编写的)。在我的一个模块中,我知道 void-pointers 指向可以从已知基类继承的类的实例,但我不能 100% 确定这一点。因此,对 void 指针执行 dynamic_cast 可能会出现问题。可能,void 指针甚至指向一个普通结构(因此结构中没有 vptr)。

我想调查 void-pointer 指向的内存的前 4 个字节,看看这是否是有效 vtable 的地址。我知道这是平台,甚至可能是特定于编译器版本的,但它可以帮助我推动应用程序向前发展,并在有限的时间段内(比如说 3 年)摆脱所有空指针。

有没有办法获取应用程序中所有 vtable 的列表,或者检查指针是否指向有效的 vtable,以及指向 vtable 的实例是否继承自已知的基类?

4

4 回答 4

4

我想调查 void-pointer 指向的内存的前 4 个字节,看看这是否是有效 vtable 的地址。

你可以这样做,但你不能保证它会起作用。Y 甚至不知道 void* 是否会指向 vtable。上次我研究这个(5 年前)我相信一些编译器将 vtable 指针存储在实例指向的地址之前*。

我知道这是平台,甚至可能是特定于编译器版本的,

它也可能是特定于编译器选项的,具体取决于您使用的优化等等。

但它可以帮助我推动应用程序向前发展,并在有限的时间段内(比如说 3 年)摆脱所有无效指针。

这是推动应用程序向前发展的唯一选择吗?你考虑过别人吗?

有没有办法获取应用程序中所有 vtables 的列表,

不 :(

或检查指针是否指向有效 vtable 的方法,

没有标准的方式。您可以做的是在您最喜欢的调试器中打开一些类指针(或将内存转换为字节并将其记录到文件中)并比较它,看看它是否有意义。即便如此,您也不能保证您的任何数据(或应用程序中的其他指针)看起来都不够相似(当转换为字节时)会混淆您喜欢的任何代码。

以及指向 vtable 的实例是否继承自已知的基类?

又不行了。

这里有一些问题(你可能已经考虑过了)。对这些问题的回答可能会给您更多选择,或者可能会给我们提供其他建议:

  • 代码库有多大?引入全局变化是否可行,或者为此而传播的功能是否可行?

  • 您是否统一对待所有指针(即:您的源代码中是否有可以插入并添加自己的元数据的共同点?)

  • 你可以在你的源代码中改变什么?(如果您可以访问您的内存分配子程序或者可以插入您自己的子程序,例如您可以插入您自己的元数据)。

  • 如果在代码的各个部分将不同的数据类型强制转换为 void*,那么以后如何确定这些指针中的内容?您可以使用区分 void* 的代码来确定它们是否是类吗?

  • 您的代码库是否允许重构方法?(在小迭代中重构,通过插入部分代码的替代实现,然后删除初始实现并测试所有内容)

编辑(建议的解决方案):

执行以下步骤:

  • 定义元数据(基)类

  • 用仅引用标准/旧例程的自定义例程替换您的内存分配例程(并确保您的代码仍然适用于自定义例程)。

  • 在每次分配时,分配the requested size + sizeof(Metadata*)(并确保您的代码仍然有效)。

  • 用您可以轻松测试的标准字节序列替换分配的第一个 sizeof(Metadata*)字节(我偏爱 0xDEADBEEF :D)。然后,返回[allocated address] + sizeof(Metadata*)应用程序。在释放时,获取接收到的指针,将其减 `sizeof(Metadata*),然后调用系统/上一个例程来执行释放。现在,您在代码中分配了一个额外的缓冲区,专门用于每次分配的元数据。

  • 在您对元数据感兴趣的情况下,创建/获取元数据类指针,然后将其设置在 0xDEADBEEF 区域中。当您需要检查元数据时reinterpret_cast<Metadata*>([your void* here]),将其递减,然后检查指针值是否为 0xDEADBEEF(无元数据)或其他值。

请注意,此代码应该只用于重构 - 对于生产代码,它很慢,容易出错,并且通常是您不希望生产代码出现的其他坏事。我会让所有这些代码依赖于一些REFACTORING_SUPPORT_ENABLED宏,这些宏永远不会让您的元数据类看到生产版本的光芒(可能除了测试版本)。

于 2010-06-14T08:40:14.700 回答
0

更简单的方法是operator new为您的特定基类重载。这样,如果您知道您的 void* 指针指向堆对象,那么您也可以 100% 确定它们是否指向您的对象。

于 2010-06-14T11:13:16.980 回答
0

我会说没有相关参考(标题声明)是不可能的。

于 2010-06-14T07:41:07.100 回答
0

如果您想将那些 void 指针替换为正确的接口类型,我认为可以将其自动化:

  1. 浏览您的代码库以获取所有具有虚函数的类的列表,您可以通过编写脚本来快速完成此操作,例如 Perl

  2. 编写一个以 void* 指针作为输入的函数,并遍历这些类尝试对其进行动态转换,如果成功则记录信息,例如接口类型、代码行

  3. 在您使用 void* 指针的任何地方调用此函数,也许您可​​以用宏包装它,这样您就可以轻松获取文件、行信息

  4. 运行完全自动化(如果有的话)并分析输出。

于 2010-06-14T07:55:36.957 回答