Невероятно, сколько вводящей в заблуждение информации вы можете прочитать в статьях выше ...
И даже в документации Microsoft msdn IsBadPtr заявлено, что он заблокирован. Ну да ладно, я предпочитаю работающее приложение, а не сбой. Даже если срок работы может работать некорректно (до тех пор, пока конечный пользователь может продолжать работу с приложением).
Погуглил, я не нашел полезного примера для Windows - нашел решение для 32-битных приложений,
http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetect%v&rt&rt&obl=deppsdrc_ddc&rt&hl=ru&obddd_db_db_ddc&b_db_db_db_db_d_d_db_d_db_d_d_dd_d_d_dd_d_d_d_d_d_d_d_d_d_d_d_db_d_b_d_0_db_d_b_d_db_d_d_d_d_d_ddd = 2
но мне также нужна поддержка 64-битных приложений, поэтому это решение мне не подошло.
Но я собрал исходные коды Wine и сумел создать аналогичный код, который будет работать и для 64-битных приложений - прикрепив код сюда:
#include <typeinfo.h>
typedef void (*v_table_ptr)();
typedef struct _cpp_object
{
v_table_ptr* vtable;
} cpp_object;
#ifndef _WIN64
typedef struct _rtti_object_locator
{
unsigned int signature;
int base_class_offset;
unsigned int flags;
const type_info *type_descriptor;
} rtti_object_locator;
#else
typedef struct
{
unsigned int signature;
int base_class_offset;
unsigned int flags;
unsigned int type_descriptor;
unsigned int type_hierarchy;
unsigned int object_locator;
} rtti_object_locator;
#endif
static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr)
{
cpp_object* cppobj = (cpp_object*) inptr;
const rtti_object_locator* obj_locator = 0;
if (!IsBadReadPtr(cppobj, sizeof(void*)) &&
!IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) &&
!IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator)))
{
obj_locator = (rtti_object_locator*) cppobj->vtable[-1];
}
return obj_locator;
}
И следующий код может определить, действителен ли указатель или нет, вам, вероятно, нужно добавить некоторую проверку NULL:
CTest* t = new CTest();
const rtti_object_locator* ptr = RTTI_GetObjectLocator(t);
#ifdef _WIN64
char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
const type_info *td = (const type_info*)(base + ptr->type_descriptor);
#else
const type_info *td = ptr->type_descriptor;
#endif
const char* n =td->name();
Это получает имя класса из указателя - я думаю, этого должно быть достаточно для ваших нужд.
Одна вещь, которую я все еще боюсь, - это производительность проверки указателя - в фрагменте кода выше уже сделано 3-4 вызова API - может быть излишним для критичных по времени приложений.
Было бы хорошо, если бы кто-нибудь мог измерить накладные расходы на проверку указателя по сравнению, например, с вызовами C # / управляемым C ++.