c++ - 有没有直接的方法可以在编译时获取vtable的地址?

标签 c++ gcc polymorphism vtable

我正在调试一个有害的内存损坏错误,该错误看起来像是指向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;
}

是否有更直接的方式来表达我想要特定类型(如 FooBar)的 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/

相关文章:

java - java中的参数多态性与简单示例

javascript - JavaScript 中的方法继承

c++ - 添加 std::string 定义会导致访问冲突

c++ - 使用虚拟纯函数访问字段的段错误

c++ - 为什么可以通过 const 左值引用传递右值?

gcc - fatal error : stdio. h:macOS 上没有这样的文件或目录

c++ - 将项目添加到 QStandardItemModel 中的列

c - GCC ARM 链接器错误 - 未定义对 'strcmp' 的引用

c - 获取可执行文件中文本部分的开始和结束地址

c++ - 具有多态模板参数的多态模板类