Es increíble la cantidad de información engañosa que puede leer en los artículos anteriores ...
E incluso en la documentación de microsoft msdn, se afirma que IsBadPtr está prohibido. Bueno, prefiero la aplicación en funcionamiento en lugar de fallar. Incluso si el trabajo temporal puede estar funcionando incorrectamente (siempre que el usuario final pueda continuar con la aplicación).
Al buscar en Google, no encontré ningún ejemplo útil para Windows: encontré una solución para aplicaciones de 32 bits,
http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetectDriver%2Fsrc%t2FDetectDriver%2Fsrcpp%t2FDbD88 = 2
pero también necesito admitir aplicaciones de 64 bits, por lo que esta solución no funcionó para mí.
Pero he cosechado los códigos fuente de Wine y me las arreglé para cocinar un tipo de código similar que también funcionaría para aplicaciones de 64 bits, adjuntando el código aquí:
#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;
}
Y el siguiente código puede detectar si el puntero es válido o no, probablemente necesite agregar alguna verificación 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();
Esto obtiene el nombre de la clase del puntero; creo que debería ser suficiente para sus necesidades.
Una cosa que todavía me temo es que el rendimiento de la comprobación del puntero (en el fragmento de código anterior ya se están realizando 3-4 llamadas a la API) podría ser excesivo para las aplicaciones de tiempo crítico.
Sería bueno si alguien pudiera medir la sobrecarga de la comprobación del puntero en comparación, por ejemplo, con las llamadas C # / administradas en C ++.