我试图访问 C++ 多态 class 的 vtable,但由于核心转储而失败,为什么?
I tried to visit vtable of a C++ polymorphic class, but failed with core dump, why?
我想用一个小程序来检测vtable的特性。我知道对于大多数流行的编译器,它们将生成其头部前导 size_t 的对象作为指向 vtable 的指针。所以我尝试转换这个指针并用它来直接调用函数。
typedef void (*pf)();
struct C
{
virtual void f(){
printf("weird\n");
}
};
int main()
{
C c1;
C* p=&c1;
pf* pvtable=(pf*)p;
pf func1=pvtable[0];
(*func1)();
return 0;
}
我希望 (*func1)() 能够打印出 "weird"。但实际结果是核心转储。
我的程序哪里出错了?
谢谢
更新:
你这里有误:
pf* pvtable=(pf*)p;
您正在将指向对象 C
的指针转换为指向 vtable 的指针。因此,您将 C
对象的内容解释为 vtable。相反,您需要更进一步地进行间接访问;将指向 C
的指针转换为指向 vtable 的指针并取消引用它:
pf* pvtable=*(pf**)p;
通过这种方式,您将跟随存储在 C
对象开头的指针指向实际的 vtable。
我原来的答案重写了更多:
#include <iostream>
struct C
{
virtual void f()
{
std::cout << "weird" << std::endl;
}
};
typedef void** C_vtable;
typedef void (C_f)(C* thiz);
int main()
{
// Create the object on stack
C c1;
// Reinterpret its address to an address of a virtual table and dereference it.
C_vtable vtable = *reinterpret_cast<C_vtable*>(&c1);
// Pick the first pointer from the virtual table and reinterpret it as our function
C_f *func1 = reinterpret_cast<C_f*>(vtable[0]);
// Call it
(*func1)(&c1);
return 0;
}
这至少适用于 Linux 上的 gcc 和 clang,也可能适用于其他编译器。但它取决于实现!
我想用一个小程序来检测vtable的特性。我知道对于大多数流行的编译器,它们将生成其头部前导 size_t 的对象作为指向 vtable 的指针。所以我尝试转换这个指针并用它来直接调用函数。
typedef void (*pf)();
struct C
{
virtual void f(){
printf("weird\n");
}
};
int main()
{
C c1;
C* p=&c1;
pf* pvtable=(pf*)p;
pf func1=pvtable[0];
(*func1)();
return 0;
}
我希望 (*func1)() 能够打印出 "weird"。但实际结果是核心转储。
我的程序哪里出错了? 谢谢
更新:
你这里有误:
pf* pvtable=(pf*)p;
您正在将指向对象 C
的指针转换为指向 vtable 的指针。因此,您将 C
对象的内容解释为 vtable。相反,您需要更进一步地进行间接访问;将指向 C
的指针转换为指向 vtable 的指针并取消引用它:
pf* pvtable=*(pf**)p;
通过这种方式,您将跟随存储在 C
对象开头的指针指向实际的 vtable。
我原来的答案重写了更多:
#include <iostream>
struct C
{
virtual void f()
{
std::cout << "weird" << std::endl;
}
};
typedef void** C_vtable;
typedef void (C_f)(C* thiz);
int main()
{
// Create the object on stack
C c1;
// Reinterpret its address to an address of a virtual table and dereference it.
C_vtable vtable = *reinterpret_cast<C_vtable*>(&c1);
// Pick the first pointer from the virtual table and reinterpret it as our function
C_f *func1 = reinterpret_cast<C_f*>(vtable[0]);
// Call it
(*func1)(&c1);
return 0;
}
这至少适用于 Linux 上的 gcc 和 clang,也可能适用于其他编译器。但它取决于实现!