2010-06-14 2 views
0

В моем приложении у меня есть довольно некоторые указатели на пустоты (это из-за исторических причин, приложение изначально было написано в чистом C). В одном из моих модулей я знаю, что указатели void указывают на экземпляры классов, которые могут наследоваться от известного базового класса, но я не могу быть на 100% уверен в этом. Следовательно, выполнение dynamic_cast на указателе void может дать проблемы. Вероятно, указатель void даже указывает на plain-struct (так что нет vptr в структуре).Получение списка всех существующих vtables

Я хотел бы исследовать первые 4 байта памяти, на которые указывает указатель void, чтобы увидеть, является ли это адресом действительной таблицы vtable. Я знаю, что это платформа, может быть, даже специфичная для компилятора версия, но она может помочь мне в продвижении приложения вперед и избавиться от всех указателей пустоты в течение ограниченного периода времени (скажем, 3 года).

Есть ли способ получить список всех vtables в приложении или способ проверить, указывает ли указатель на действительную таблицу vtable и наследует ли этот экземпляр на vtable от известного базового класса?

ответ

4

Я хотел бы исследовать первые 4 байта памяти пустоты-указатель который указует, чтобы увидеть, если это адрес действующих виртуальных таблиц.

Вы можете это сделать, но у вас нет никаких гарантий, что это будет работать. Я даже не знаю, будет ли void * указывать на vtable. В прошлый раз, когда я смотрел на это (5+ лет назад), я считаю, что некоторый компилятор сохранил указатель vtable до адрес, на который указывает экземпляр *.

Я знаю, что это платформа, может быть, даже компилятором конкретной версии,

Он также может быть компилятором варианты speciffic, в зависимости от того, какие оптимизации вы используете, и так далее.

, но это может помочь мне в продвижении приложения вперед, и избавиться от всех недействительных указателей в течение ограниченного периода времени (скажем, 3 лет).

Это единственный вариант, который вы можете увидеть для перемещения приложения вперед? Вы считали других? не

Есть ли способ, чтобы получить список всех виртуальных таблиц в приложении,

Нет :(

или способ проверить, является ли указатель указывает на действительный vtable,

Нет стандартного способа. Что вы можете сделать, так это открыть некоторые указатели на классы в вашем любимом debu gger (или отложите память на байты и запишите ее в файл), и сравните ее и посмотрите, имеет ли смысл. Тем не менее, у вас нет гарантий, что никакие ваши данные (или другие указатели в приложении) не будут выглядеть достаточно похожими (при использовании в виде байтов), чтобы запутать любой код, который вам нравится.

и является ли этот экземпляр, указывающий на на виртуальные таблицы наследует от известного базового класса ?

Нет снова.

Вот несколько вопросов (возможно, вы уже их рассмотрели). Ответы на них могут дать вам больше возможностей или могут дать нам другие идеи:

  • , насколько велика кодовая база? Возможно ли внедрить глобальные изменения или это функциональность для распространения?

  • вы относитесь все указатели равномерно (то есть: есть ли общие точки в исходном коде, где можно подключить и добавить свои собственные метаданные)

  • , что вы можете изменить в исходном коде? (Если у вас есть доступ к вашим подпрограммам распределения памяти или вы можете подключить свои собственные, например, вы можете подключить свои собственные метаданные).

  • Если разные типы данных отлиты от void * в различных частях вашего кода, как вы позже определяете, что находится в этих указателях? Можете ли вы использовать код, который различает void *, чтобы решить, являются ли они классами или нет?

  • Предоставляет ли ваша кодовая база методологии рефакторинга? (Рефакторинг в малых итерациях, путь подключения альтернативных реализаций для частей коды, того удаления первоначальной реализации и тестирования всего)

Редактировать (предлагаемое решение):

Выполните следующие действия:

  • определяют метаданные (базовый) класс

  • заменить вашу подпрограммы распределения памяти с пользовательскими, которые относятся только к стандартным/старым процедурам (и убедитесь, что ваш код по-прежнему работает с пользовательскими подпрограммами).

  • при каждом размещении, укажите the requested size + sizeof(Metadata*) (и убедитесь, что код по-прежнему работает).

  • заменить первыеsizeof(Metadata*) байт вашего выделения со стандартной последовательности байтов, которые вы можете легко проверить для (я неравнодушен к 0xDEADBEEF: D). Затем верните [allocated address] + sizeof(Metadata*) в приложение. При освобождении возьмите полученный указатель, уменьшите его на sizeof (метаданные *), затем вызовите системную/предыдущую процедуру для выполнения освобождения. Теперь у у вас есть дополнительный буфер, выделенный в вашем коде, в частности для метаданных по каждому распределению.

  • В случаях, когда вы заинтересованы в наличии метаданных, создайте/получите указатель класса метаданных, а затем установите его в зоне 0xDEADBEEF. Когда вам нужно проверить метаданные, reinterpret_cast<Metadata*>([your void* here]), уменьшите его, а затем проверьте, равно ли значение указателя 0xDEADBEEF (без метаданных) или что-то еще.

Обратите внимание, что этот код должен быть только там для рефакторинга - для производства кода это очень медленный процесс, к ошибкам и вообще другие плохие вещи, которые вы не хотите, чтобы ваш код продукции будет. Я бы сделал весь этот код зависимым от некоторого REFACTORING_SUPPORT_ENABLED макроса, который никогда не позволил бы вашему классу метаданных видеть свет производственного выпуска (за исключением, возможно, тестирования сборки).

+0

По всем вашим вопросам: да, я могу реорганизовать и многое изменить. Но я действительно искал трюки, поэтому части программного обеспечения могут работать с указателями void (во время перехода) или способами поиска проблем (в случае, если некоторые указатели void были «забыты»). – Patrick

+1

См. Мое изменение выше для решения. – utnapistim

+0

Отличная идея. К счастью, у меня даже есть опыт работы с пользовательскими процедурами распределения, поэтому это должно быть довольно легко реализовать. Благодарю. – Patrick

0

Я бы сказал, что это невозможно без ссылки (объявление заголовка).

0

Если вы хотите, чтобы заменить эти недействительные указатели на правильный тип интерфейса, вот что я думаю, автоматизировать его:

  1. Переход через кодовый, чтобы получить список всех классов, имеют виртуальные функции, вам мог бы сделать это быстро, написав скрипт, например Perl

  2. Напишите функцию, которая вводит указатель void * в качестве входных данных, а также итерация по этим классам пытается выполнить динамическое_сканирование и данные журнала, если это удалось, например тип интерфейса, строка кода

  3. Вызовите эту функцию в любом месте, где вы использовали указатель void *, возможно, вы могли бы обернуть его макросом, чтобы вы могли получить файл, легко получить информацию о линии

  4. Запустите полную автоматизацию (если есть) и проанализируйте выход.

+2

Вы не можете динамически перемещать указатель на пустоту. – 2010-06-14 07:58:41

+0

действительно? Я даже этого не замечал, поэтому, если у меня есть указатель на void, что бы я сделал, если бы знал, что он указывает на какой-то интерфейс и хочет ли он на него наброситься? –

+0

Почему у вас есть указатель на пустоту в первую очередь? Конечно, вы можете (по-динамически) отбрасывать указатель void на базовый указатель (или что-то еще), но это побеждает объект этого конкретного упражнения. – 2010-06-14 08:05:48

0

Более простой способ - перегрузить operator new для вашего базового класса. Таким образом, если вы знаете, что ваши указатели void * предназначены для кучи объектов, вы также можете со 100% уверенностью определить, указывают ли они на ваш объект.

Смежные вопросы