Search code examples
c++pointerspolymorphismvirtualvtable

I tried to visit vtable of a C++ polymorphic class, but failed with core dump, why?


I wish to use a small program to detect the feature of vtable. I know for most popular compilers, they'll generate objects with leading size_t of its head to be a pointer to vtable. So I tried to convert this pointer and use it for a direct function call.

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

I wish that (*func1)() will print out "weird". But the actural result was core dump.

Where did I get wrong in my program? Thanks.


Solution

  • Update:

    You have a mistake here:

    pf* pvtable=(pf*)p;
    

    You are casting the pointer to object C to a pointer to vtable. Therefore you are interpreting the content of the C object as a vtable. Instead you need to go one indirection further; cast the pointer to C to a pointer-to-pointer to vtable and dereference it:

    pf* pvtable=*(pf**)p;
    

    This way you will follow the pointer stored at the beginning of C object to the actual vtable.


    My original answer that is rewriten more:

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

    This will work at least with gcc and clang on Linux, possible with other compilers too. But it is implementation dependent!