Указатель экземпляра отличается от vfptr при загрузке.dll
Итак, я поиграл с Visual Studio Test Suite и обнаружил кое-что интересное:
У меня есть экземпляр для класса А по адресу, скажем, 0x0656a64c
, Затем, когда я наблюдал за переменной, он говорит, что его __vfptr
указывает на 0x077e7c0c
,
Насколько я знаю, указатель виртуальной таблицы класса должен располагаться в первых 4 байтах (или 8 байтах в 64-битных приложениях) экземпляра класса, если только это не случай множественного наследования (тогда это просто смещения 1-го числа). адрес vtable).
Я заметил, что Visual Studio скомпилировал мой тест в.dll и динамически загружал свои инструменты для загрузки.dll.
Может ли это быть причиной различий в адресе?
Вот скриншот VS отладчика
2 ответа
Вы путаете адрес vptr и адрес, на который указывает vptr. Вы (примерно) правы, что обычная реализация состоит в том, что vptr - это первое, что есть в объекте, но Visual Studio показывает вам адрес виртуальной таблицы (который является общим для всех объектов класса).
Это нормальное поведение для компилятора MS C++. 2 DLL, которые создают экземпляры одного и того же объекта класса, будут иметь разные vtables. Интуиция подсказывает, что vtable должна использоваться всеми экземплярами независимо от того, какой (новый) код DLL ее создал. Он должен быть общим для реализации класса. Не правда.
Это создает опасность, когда DLL освобождается динамически. Все выделенные объекты могут по-прежнему находиться в допустимой (процессной) куче. Но если у него есть виртуальный деструктор, он определен в vtable. Теперь он находится в освобожденном пространстве. Итак, vtable поврежден. Любое его использование вызовет исключение.
Решение состоит в том, чтобы очистить все / все выделения, сделанные динамической DLL, которая также может иметь vtable (например, виртуальный деструктор), перед освобождением DLL. Любые выделения, сделанные в куче процесса, которые не указывают на виртуальную таблицу на основе DLL, в порядке. Худший случай - это утечка памяти, если ее не отследить должным образом.