Я хотел бы исследовать первые 4 байта памяти, на которые указывает указатель void, чтобы узнать, является ли это адресом действительной vtable.
Вы можете это сделать, но у вас нет никаких гарантий, что это сработает. Y даже не знает, будет ли void* указывать на vtable. В прошлый раз, когда я изучал это (более 5 лет назад), я полагаю, что какой-то компилятор сохранил указатель vtable перед адресом, на который указывает экземпляр *.
Я знаю, что это платформа, может быть, даже зависит от версии компилятора,
Это также может быть связано с параметрами компилятора, в зависимости от того, какие оптимизации вы используете и так далее.
но это может помочь мне в продвижении приложения и избавлении от всех указателей на пустоту за ограниченный период времени (скажем, 3 года).
Это единственный вариант, который вы видите для продвижения приложения вперед? Вы рассматривали других?
Есть ли способ получить список всех vtables в приложении,
No :(
или способ проверить, указывает ли указатель на действительную виртуальную таблицу,
Нет стандартного способа. Что вы можете сделать, так это открыть некоторые указатели классов в своем любимом отладчике (или преобразовать память в байты и записать ее в файл), сравнить их и посмотреть, имеет ли это смысл. Тем не менее, у вас нет гарантий, что любые ваши данные (или другие указатели в приложении) не будут выглядеть достаточно похожими (при преобразовании в байты), чтобы запутать любой код, который вам нравится.
и наследуется ли этот экземпляр, указывающий на vtable, от известного базового класса?
Нет снова.
Вот несколько вопросов (возможно, вы уже обдумывали их). Ответы на них могут дать вам больше вариантов или могут дать нам другие идеи, чтобы предложить:
насколько велика кодовая база? Возможно ли внести глобальные изменения, или для этого нужно распространить функциональность?
относитесь ли вы ко всем указателям единообразно (то есть: есть ли в вашем исходном коде общие точки, в которые вы могли бы вставлять и добавлять свои собственные метаданные?)
что вы можете изменить в исходном коде? (Если у вас есть доступ к вашим подпрограммам распределения памяти или вы можете подключить свои собственные, например, вы можете подключить свои собственные метаданные).
Если разные типы данных приводятся к void* в разных частях вашего кода, как вы потом решаете, что находится в этих указателях? Можете ли вы использовать код, различающий void*, чтобы решить, являются ли они классами или нет?
Поддерживает ли ваша кодовая база методологии рефакторинга? (рефакторинг небольшими итерациями, путем добавления альтернативных реализаций для частей вашего кода, затем удаления исходной реализации и тестирования всего)
Изменить (предлагаемое решение):
Выполните следующие действия:
определить класс метаданных (базовый)
замените свои процедуры выделения памяти пользовательскими, которые просто ссылаются на стандартные/старые процедуры (и убедитесь, что ваш код все еще работает с пользовательскими процедурами).
при каждом выделении выделяйте the requested size + sizeof(Metadata*)
(и убедитесь, что ваш код все еще работает).
замените первые sizeof(Metadata*)
байта вашего распределения стандартной последовательностью байтов, которую вы можете легко проверить (я неравнодушен к 0xDEADBEEF :D). Затем верните [allocated address] + sizeof(Metadata*)
в приложение. При освобождении возьмите полученный указатель, уменьшите его на `sizeof(Metadata*), затем вызовите системную/предыдущую подпрограмму для выполнения освобождения. Теперь у вас есть дополнительный буфер, выделенный в вашем коде, специально для метаданных при каждом выделении.
В тех случаях, когда вам нужны метаданные, создайте/получите указатель класса метаданных, а затем установите его в зоне 0xDEADBEEF. Когда вам нужно проверить метаданные, reinterpret_cast<Metadata*>([your void* here])
, уменьшить их, а затем проверить, равно ли значение указателя 0xDEADBEEF (нет метаданных) или чему-то еще.
Обратите внимание, что этот код должен быть там только для рефакторинга — для производственного кода он медленный, подвержен ошибкам и, как правило, другим плохим вещам, которых вы не хотите, чтобы ваш производственный код был. Я бы сделал весь этот код зависимым от некоторого макроса REFACTORING_SUPPORT_ENABLED
, который никогда не позволит вашему классу метаданных увидеть свет производственной версии (за исключением, может быть, тестовых сборок).
person
utnapistim
schedule
14.06.2010