0

a simple example code as below:

#include <iostream>

class Base
{
public:
    virtual void func0() { std::cout << "Base::func0" << std::endl; };
    virtual void func1() { std::cout << "Base::func1" << std::endl; };
};


int main()
{
    auto instance = Base();
    uint64_t* vtableAddr = reinterpret_cast<uint64_t*>(&instance);
    uint64_t* pVtable = reinterpret_cast<uint64_t*>(*vtableAddr);
    auto func0 = reinterpret_cast<void(*)(Base*)>(*(pVtable + 0));
    auto func1 = reinterpret_cast<void(*)(Base*)>(*(pVtable + 1));
    func0(&instance);
    func1(&instance);

    auto func2 = reinterpret_cast<void(*)(Base*)>(*(pVtable + 2)); // exceed the limitation
    func2(&instance); // core dump
}

I can get the virtual table address by read the class fisrt 8 bytes(64bits compiler). But I don't know if there is a way to get the max legal offset of pVtable in runtime.
As above example, if I set the offset of pVtable is 2, and invoke the converted function, it will lead to a coredump.
Is any where stored the virtual table "size" for each class?

Chen Dong
  • 23
  • 1
  • 6
  • 3
    vtable is one possible implementation but not a required implementation... What you are doing seems like a recipe for runtime surprises / faults. Suggest thinking about using a member function pointer – Mr R Mar 11 '21 at 02:55
  • func2 fails because the methods in the vtable expect a "this" pointer somewhere (even if you aren't using it). – Mr R Mar 11 '21 at 02:57
  • 2
    Is this an academic exercise or is there a specific problem you're trying to solve? – Stephen Newell Mar 11 '21 at 02:58
  • @MrR I'm just interested at the implementation of vtable, wondring if there is a runtime protect for this special usage. – Chen Dong Mar 11 '21 at 03:03
  • @StephenNewell no exactlly problem exist, I just want to know. :) – Chen Dong Mar 11 '21 at 03:04
  • 2
    A fun exercise: try counting how many instances of undefined behavior there are in that piece code. – Brian61354270 Mar 11 '21 at 03:07
  • 4
    There's no guarantee a vtable exists, and as soon as you deal with more complicated inheritance (multiple/virtual and combinations of multiple/virtual) you're going to be extremely disappointed. – Stephen Newell Mar 11 '21 at 03:08
  • 2
    The compiler doesn't need to know the limits of the vtable at runtime, because it has the full definition of the class (including the vtable size) at compile time. It won't generate code that goes beyond those limits. Doesn't prevent you from doing something stupid, though. – Mark Ransom Mar 11 '21 at 03:12
  • Related: https://stackoverflow.com/questions/1342126/virtual-table-layout-in-memory https://stackoverflow.com/questions/70682/what-is-the-vtable-layout-and-vtable-pointer-location-in-c-objects-in-gcc-3-x https://stackoverflow.com/questions/99297/how-are-virtual-functions-and-vtable-implemented – Jerry Jeremiah Mar 11 '21 at 03:16
  • 1
    And even if they do exist, different implementors do them differently ...Microsoft vs GNU for instance ... – Mr R Mar 11 '21 at 03:39
  • The only general C++ answer is that it's not safe to do any of this. There are more detailed "behind the scenes" answers, but they will depend on the particular compiler and target architecture. g++ and clang++ both use the general-purpose "Itanium ABI", MSVC uses Microsoft's own ABI, etc. – aschepler Mar 11 '21 at 05:00

1 Answers1

-1

There's no guarantee a vtable exists, and as soon as you deal with more complicated inheritance (multiple/virtual and combinations of multiple/virtual) you're going to be extremely disappointed. from @Stephen Newell

Chen Dong
  • 23
  • 1
  • 6