我正在调试一个有害的内存损坏错误,该错误看起来像是指向vtable
的指针已损坏。我想通过在程序中的各个点将指针的值与指针的正确值(vtable
的真实位置)进行比较来检测何时发生。
不幸的是,我还没有找到在编译时获取指针正确值的方法,所以我被迫实例化一个新对象只是为了读取它的vtable
指针,这似乎没有必要。
#include <iostream>
#include <iomanip>
#include <stdint.h>
class Foo {
virtual void performVirtualAction() {
std::cout << "Foo's version" << std::endl;
}
};
class Bar : public Foo {
virtual void performVirtualAction() {
std::cout << "Bar's version" << std::endl;
}
};
int main(){
Foo foo;
Bar bar;
std::cout << "Foo's vtable pointer " << std::hex << *(uint64_t*)(&foo) << std::endl;
std::cout << "Bar's vtable pointer " << std::hex << *(uint64_t*)(&bar) << std::endl;
}
是否有更直接的方式来表达我想要特定类型(如 Foo
或 Bar
)的 vtable
位置的想法?
该方法不必是可移植的。它只适用于 Linux 上的 gcc
。
最佳答案
C++ 没有定义如何实现多态性。 vtables只是事实上的标准,但是如果任何编译器供应商找到合适的不同方法,他就可以自由地做任何他想做的事。
因此,无论您尝试以编程方式执行什么操作,它始终都是一种肮脏的黑客行为,因为 vtable 是内部编译器详细信息,对 C++ 代码不直接可见。
[ 编辑:需要纠正自己:gcc 在多态类的开头放置一个指向 vtable 的指针。接下来:只需将对象转换为 uintptr_t
(不是 uint64_t
)(或指向 uintptr_t*
的指针),您将直接获得指针到虚函数表。如果您还想打印 vtable 本身(以查看该 vtable 是否已损坏),这可能会有所帮助:What is the VTable Layout and VTable Pointer Location in C++ Objects in GCC 3.x and 4.x? ]
实际上,我并不期望您会发现太多,因为您可能会在 vtable 实际发生很久之后才看到它的变化。如果您知道或可以找出哪些对象实例受到影响,您可以在 gdb 中的写访问 ( https://sourceware.org/gdb/onlinedocs/gdb/Set-Watchpoints.html ) 上添加内存观察点。这将准确揭示您的 vtable 损坏的时间和位置(例如,如果您写入超出数组定义的边界,将对象转换为错误的类型并写入它,...)。
关于c++ - 有没有直接的方法可以在编译时获取vtable的地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36766417/