как искать виртуальную таблицу С++?

простой пример кода, как показано ниже:

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

Я могу получить адрес виртуальной таблицы, прочитав класс fisrt 8 байт (64-битный компилятор). Но я не знаю, есть ли способ получить максимально допустимое смещение pVtable во время выполнения.
Как и в приведенном выше примере, если я установлю смещение pVtable равным 2 и вызову преобразованную функцию, это приведет к coredump.
Где хранится размер виртуальной таблицы для каждого класса?


person Chen Dong    schedule 11.03.2021    source источник
comment
vtable - это одна из возможных реализаций, но не обязательная реализация... То, что вы делаете, похоже на рецепт неожиданностей/ошибок во время выполнения. Предложите подумать об использовании указателя на функцию-член   -  person Mr R    schedule 11.03.2021
comment
func2 терпит неудачу, потому что методы в vtable где-то ожидают этот указатель (даже если вы его не используете).   -  person Mr R    schedule 11.03.2021
comment
Это академическое упражнение или есть конкретная проблема, которую вы пытаетесь решить?   -  person Stephen Newell    schedule 11.03.2021
comment
@MrR Меня просто интересует реализация vtable, и мне интересно, есть ли защита во время выполнения для этого специального использования.   -  person Chen Dong    schedule 11.03.2021
comment
@StephenNewell, проблемы точно не существует, я просто хочу знать. :)   -  person Chen Dong    schedule 11.03.2021
comment
Забавное упражнение: попробуйте посчитать, сколько случаев неопределенного поведения есть в этом фрагменте кода.   -  person Brian    schedule 11.03.2021
comment
Нет никакой гарантии, что виртуальная таблица существует, и как только вы столкнетесь с более сложным наследованием (множественным/виртуальным и комбинациями нескольких/виртуальных), вы будете крайне разочарованы.   -  person Stephen Newell    schedule 11.03.2021
comment
Компилятору не нужно знать пределы виртуальной таблицы во время выполнения, поскольку он имеет полное определение класса (включая размер виртуальной таблицы) во время компиляции. Он не будет генерировать код, выходящий за эти пределы. Впрочем, это не мешает вам делать глупости.   -  person Mark Ransom    schedule 11.03.2021
comment
Связано: stackoverflow.com/questions/1342126/ stackoverflow.com/questions/70682/ stackoverflow.com/questions/99297/   -  person Jerry Jeremiah    schedule 11.03.2021
comment
И даже если они существуют, разные разработчики делают их по-разному ... например, Microsoft против GNU ...   -  person Mr R    schedule 11.03.2021
comment
Единственный общий ответ C++ заключается в том, что делать что-либо из этого небезопасно. Есть более подробные ответы за кулисами, но они будут зависеть от конкретного компилятора и целевой архитектуры. g++ и clang++ используют универсальный ABI Itanium, MSVC использует собственный ABI Microsoft и т. д.   -  person aschepler    schedule 11.03.2021


Ответы (1)


Нет никакой гарантии, что виртуальная таблица существует, и как только вы столкнетесь с более сложным наследованием (множественным/виртуальным и комбинациями нескольких/виртуальных), вы будете крайне разочарованы. от @Стивен Ньюэлл

person Chen Dong    schedule 11.03.2021