有没有直接的方法在编译时获取vtable的地址?

时间:2016-04-21 10:10:06

标签: c++ gcc polymorphism vtable

我正在调试一个有害的内存损坏错误,它看起来像vtable的指针正在被破坏。我想通过比较指针的值与指针的正确值(vtable的真实位置)在我的程序中的不同点来检测它何时发生。

不幸的是,我还没有找到一种方法来在编译时获取指针的正确值,所以我被迫实例化一个新对象只是为了读取它的vtable指针,这似乎不必要的hacky。

#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;
}

是否有更直接的方式来表达我希望vtable的位置适用于FooBar等特定类型?

该方法不必是可移植的。它只需要在Linux上用于gcc

1 个答案:

答案 0 :(得分:2)

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被破坏的时间和地点(例如,如果你写的超出了数组的定义边界,将你的对象转换为错误的类型并写入它,......)。