Fixed __RTDynamicCast to return the correct pointer for multiple
inheritance hierarchies (thanks to Muse Research for help with this one). Added some debug output.
This commit is contained in:
parent
e62e88f488
commit
b8d5d962ee
|
@ -61,10 +61,8 @@ typedef struct _rtti_base_descriptor
|
|||
{
|
||||
type_info *type_descriptor;
|
||||
int num_base_classes;
|
||||
int base_class_offset;
|
||||
unsigned int flags;
|
||||
int unknown1;
|
||||
int unknown2;
|
||||
this_ptr_offsets offsets; /* offsets for computing the this pointer */
|
||||
unsigned int attributes;
|
||||
} rtti_base_descriptor;
|
||||
|
||||
typedef struct _rtti_base_array
|
||||
|
@ -74,15 +72,15 @@ typedef struct _rtti_base_array
|
|||
|
||||
typedef struct _rtti_object_hierarchy
|
||||
{
|
||||
int unknown1;
|
||||
int unknown2;
|
||||
unsigned int signature;
|
||||
unsigned int attributes;
|
||||
int array_len; /* Size of the array pointed to by 'base_classes' */
|
||||
const rtti_base_array *base_classes;
|
||||
} rtti_object_hierarchy;
|
||||
|
||||
typedef struct _rtti_object_locator
|
||||
{
|
||||
int unknown1;
|
||||
unsigned int signature;
|
||||
int base_class_offset;
|
||||
unsigned int flags;
|
||||
type_info *type_descriptor;
|
||||
|
@ -106,6 +104,30 @@ const exception_vtable MSVCRT_bad_cast_vtable;
|
|||
const exception_vtable MSVCRT___non_rtti_object_vtable;
|
||||
static const exception_vtable MSVCRT_type_info_vtable;
|
||||
|
||||
static void dump_obj_locator( const rtti_object_locator *ptr )
|
||||
{
|
||||
int i;
|
||||
const rtti_object_hierarchy *h = ptr->type_hierarchy;
|
||||
|
||||
TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n",
|
||||
ptr, ptr->signature, ptr->base_class_offset, ptr->flags,
|
||||
ptr->type_descriptor, dbgstr_type_info(ptr->type_descriptor), ptr->type_hierarchy );
|
||||
TRACE( " hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n",
|
||||
h->signature, h->attributes, h->array_len, h->base_classes );
|
||||
for (i = 0; i < h->array_len; i++)
|
||||
{
|
||||
TRACE( " base class %p: num %d off %d,%d,%d attr %08x type %p %s\n",
|
||||
h->base_classes->bases[i],
|
||||
h->base_classes->bases[i]->num_base_classes,
|
||||
h->base_classes->bases[i]->offsets.this_offset,
|
||||
h->base_classes->bases[i]->offsets.vbase_descr,
|
||||
h->base_classes->bases[i]->offsets.vbase_offset,
|
||||
h->base_classes->bases[i]->attributes,
|
||||
h->base_classes->bases[i]->type_descriptor,
|
||||
dbgstr_type_info(h->base_classes->bases[i]->type_descriptor) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal common ctor for exception */
|
||||
static void WINAPI EXCEPTION_ctor(exception *_this, const char** name)
|
||||
{
|
||||
|
@ -641,9 +663,7 @@ static const rtti_base_descriptor exception_rtti_base_descriptor =
|
|||
{
|
||||
&exception_type_info,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -677,9 +697,7 @@ static const cxx_type_info exception_cxx_type_info =
|
|||
{
|
||||
0,
|
||||
&exception_type_info,
|
||||
0,
|
||||
-1,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
sizeof(exception),
|
||||
(cxx_copy_ctor)__thiscall_MSVCRT_exception_copy_ctor
|
||||
};
|
||||
|
@ -695,9 +713,7 @@ static const rtti_base_descriptor bad_typeid_rtti_base_descriptor =
|
|||
{
|
||||
&bad_typeid_type_info,
|
||||
1,
|
||||
0,
|
||||
0xffffffff,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -731,9 +747,7 @@ static const cxx_type_info bad_typeid_cxx_type_info =
|
|||
{
|
||||
0,
|
||||
&bad_typeid_type_info,
|
||||
0,
|
||||
-1,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
sizeof(exception),
|
||||
(cxx_copy_ctor)__thiscall_MSVCRT_bad_typeid_copy_ctor
|
||||
};
|
||||
|
@ -749,9 +763,7 @@ static const rtti_base_descriptor bad_cast_rtti_base_descriptor =
|
|||
{
|
||||
&bad_cast_type_info,
|
||||
1,
|
||||
0,
|
||||
0xffffffff,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -785,9 +797,7 @@ static const cxx_type_info bad_cast_cxx_type_info =
|
|||
{
|
||||
0,
|
||||
&bad_cast_type_info,
|
||||
0,
|
||||
-1,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
sizeof(exception),
|
||||
(cxx_copy_ctor)__thiscall_MSVCRT_bad_cast_copy_ctor
|
||||
};
|
||||
|
@ -803,9 +813,7 @@ static const rtti_base_descriptor __non_rtti_object_rtti_base_descriptor =
|
|||
{
|
||||
&__non_rtti_object_type_info,
|
||||
2,
|
||||
0,
|
||||
0xffffffff,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -839,9 +847,7 @@ static const cxx_type_info __non_rtti_object_cxx_type_info =
|
|||
{
|
||||
0,
|
||||
&__non_rtti_object_type_info,
|
||||
0,
|
||||
-1,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
sizeof(exception),
|
||||
(cxx_copy_ctor)__thiscall_MSVCRT___non_rtti_object_copy_ctor
|
||||
};
|
||||
|
@ -857,9 +863,7 @@ static const rtti_base_descriptor type_info_rtti_base_descriptor =
|
|||
{
|
||||
&type_info_type_info,
|
||||
0,
|
||||
0,
|
||||
0xffffffff,
|
||||
0,
|
||||
{ 0, -1, 0 },
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -1150,13 +1154,16 @@ void* MSVCRT___RTDynamicCast(type_info *cppobj, int unknown,
|
|||
const rtti_object_locator *obj_locator;
|
||||
|
||||
/* Note: cppobj _isn't_ a type_info, we use that struct for its vtable ptr */
|
||||
TRACE("(%p,%d,%p,%p,%d)\n", cppobj, unknown, src, dst, do_throw);
|
||||
TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n",
|
||||
cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw);
|
||||
if (!cppobj)
|
||||
return 0;
|
||||
obj_locator= RTTI_GetObjectLocator(cppobj);
|
||||
if (unknown)
|
||||
FIXME("Unknown parameter is non-zero: please report\n");
|
||||
|
||||
if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator);
|
||||
|
||||
/* To cast an object at runtime:
|
||||
* 1.Find out the true type of the object from the typeinfo at vtable[-1]
|
||||
* 2.Search for the destination type in the class hierarchy
|
||||
|
@ -1176,8 +1183,9 @@ void* MSVCRT___RTDynamicCast(type_info *cppobj, int unknown,
|
|||
|
||||
if (!strcmp(typ->mangled, dst->mangled))
|
||||
{
|
||||
dst_offset = (*base_desc)->base_class_offset;
|
||||
break;
|
||||
/* compute the correct this pointer for that base class */
|
||||
void *this_ptr = (char *)cppobj - obj_locator->base_class_offset;
|
||||
return get_this_pointer( &(*base_desc)->offsets, this_ptr );
|
||||
}
|
||||
base_desc++;
|
||||
count++;
|
||||
|
|
|
@ -76,12 +76,12 @@ inline static void call_dtor( void *func, void *object )
|
|||
__asm__ __volatile__("call *%0" : : "r" (func), "c" (object) : "eax", "edx", "memory" );
|
||||
}
|
||||
|
||||
static void dump_type( const cxx_type_info *type )
|
||||
static inline void dump_type( const cxx_type_info *type )
|
||||
{
|
||||
DPRINTF( "flags %x type %p", type->flags, type->type_info );
|
||||
if (type->type_info) DPRINTF( " (%p %s)", type->type_info->name, type->type_info->mangled );
|
||||
DPRINTF( " offset %d vbase %d,%d size %d copy ctor %p\n", type->this_offset,
|
||||
type->vbase_descr, type->vbase_offset, type->size, type->copy_ctor );
|
||||
DPRINTF( "flags %x type %p %s offsets %d,%d,%d size %d copy ctor %p\n",
|
||||
type->flags, type->type_info, dbgstr_type_info(type->type_info),
|
||||
type->offsets.this_offset, type->offsets.vbase_descr, type->offsets.vbase_offset,
|
||||
type->size, type->copy_ctor );
|
||||
}
|
||||
|
||||
static void dump_exception_type( const cxx_exception_type *type )
|
||||
|
@ -121,33 +121,13 @@ static void dump_function_descr( const cxx_function_descr *descr, const cxx_exce
|
|||
for (j = 0; j < descr->tryblock[i].catchblock_count; j++)
|
||||
{
|
||||
catchblock_info *ptr = &descr->tryblock[i].catchblock[j];
|
||||
DPRINTF( " %d: flags %x offset %d handler %p type %p",
|
||||
j, ptr->flags, ptr->offset, ptr->handler, ptr->type_info );
|
||||
if (ptr->type_info) DPRINTF( " (%p %s)", ptr->type_info->name, ptr->type_info->mangled );
|
||||
DPRINTF( "\n" );
|
||||
DPRINTF( " %d: flags %x offset %d handler %p type %p %s\n",
|
||||
j, ptr->flags, ptr->offset, ptr->handler,
|
||||
ptr->type_info, dbgstr_type_info( ptr->type_info ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* compute the this pointer for a base class of a given type */
|
||||
static void *get_this_pointer( const cxx_type_info *type, void *object )
|
||||
{
|
||||
void *this_ptr;
|
||||
int *offset_ptr;
|
||||
|
||||
if (!object) return NULL;
|
||||
this_ptr = (char *)object + type->this_offset;
|
||||
if (type->vbase_descr >= 0)
|
||||
{
|
||||
/* move this ptr to vbase descriptor */
|
||||
this_ptr = (char *)this_ptr + type->vbase_descr;
|
||||
/* and fetch additional offset from vbase descriptor */
|
||||
offset_ptr = (int *)(*(char **)this_ptr + type->vbase_offset);
|
||||
this_ptr = (char *)this_ptr + *offset_ptr;
|
||||
}
|
||||
return this_ptr;
|
||||
}
|
||||
|
||||
/* check if the exception type is caught by a given catch block, and return the type that matched */
|
||||
static const cxx_type_info *find_caught_type( cxx_exception_type *exc_type, catchblock_info *catchblock )
|
||||
{
|
||||
|
@ -185,21 +165,21 @@ static void copy_exception( void *object, cxx_exception_frame *frame,
|
|||
|
||||
if (catchblock->flags & TYPE_FLAG_REFERENCE)
|
||||
{
|
||||
*dest_ptr = get_this_pointer( type, object );
|
||||
*dest_ptr = get_this_pointer( &type->offsets, object );
|
||||
}
|
||||
else if (type->flags & CLASS_IS_SIMPLE_TYPE)
|
||||
{
|
||||
memmove( dest_ptr, object, type->size );
|
||||
/* if it is a pointer, adjust it */
|
||||
if (type->size == sizeof(void *)) *dest_ptr = get_this_pointer( type, *dest_ptr );
|
||||
if (type->size == sizeof(void *)) *dest_ptr = get_this_pointer( &type->offsets, *dest_ptr );
|
||||
}
|
||||
else /* copy the object */
|
||||
{
|
||||
if (type->copy_ctor)
|
||||
call_copy_ctor( type->copy_ctor, dest_ptr, get_this_pointer(type,object),
|
||||
call_copy_ctor( type->copy_ctor, dest_ptr, get_this_pointer(&type->offsets,object),
|
||||
(type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) );
|
||||
else
|
||||
memmove( dest_ptr, get_this_pointer(type,object), type->size );
|
||||
memmove( dest_ptr, get_this_pointer(&type->offsets,object), type->size );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,16 +84,22 @@ typedef struct __cxx_function_descr
|
|||
|
||||
typedef void (*cxx_copy_ctor)(void);
|
||||
|
||||
/* complete information about a C++ type */
|
||||
typedef struct __cxx_type_info
|
||||
/* offsets for computing the this pointer */
|
||||
typedef struct
|
||||
{
|
||||
UINT flags; /* flags (see CLASS_* flags below) */
|
||||
type_info *type_info; /* C++ type info */
|
||||
int this_offset; /* offset of base class this pointer from start of object */
|
||||
int vbase_descr; /* offset of virtual base class descriptor */
|
||||
int vbase_offset; /* offset of this pointer offset in virtual base class descriptor */
|
||||
size_t size; /* object size */
|
||||
cxx_copy_ctor copy_ctor; /* copy constructor */
|
||||
} this_ptr_offsets;
|
||||
|
||||
/* complete information about a C++ type */
|
||||
typedef struct __cxx_type_info
|
||||
{
|
||||
UINT flags; /* flags (see CLASS_* flags below) */
|
||||
type_info *type_info; /* C++ type info */
|
||||
this_ptr_offsets offsets; /* offsets for computing the this pointer */
|
||||
size_t size; /* object size */
|
||||
cxx_copy_ctor copy_ctor; /* copy constructor */
|
||||
} cxx_type_info;
|
||||
#define CLASS_IS_SIMPLE_TYPE 1
|
||||
#define CLASS_HAS_VIRTUAL_BASE_CLASS 4
|
||||
|
@ -121,4 +127,30 @@ typedef struct __cxx_exception_type
|
|||
|
||||
void _CxxThrowException(void*,const cxx_exception_type*);
|
||||
|
||||
static inline const char *dbgstr_type_info( const type_info *info )
|
||||
{
|
||||
if (!info) return "{}";
|
||||
return wine_dbg_sprintf( "{vtable=%p name=%s (%s)}",
|
||||
info->vtable, info->mangled, info->name ? info->name : "" );
|
||||
}
|
||||
|
||||
/* compute the this pointer for a base class of a given type */
|
||||
static inline void *get_this_pointer( const this_ptr_offsets *off, void *object )
|
||||
{
|
||||
void *this_ptr;
|
||||
int *offset_ptr;
|
||||
|
||||
if (!object) return NULL;
|
||||
this_ptr = (char *)object + off->this_offset;
|
||||
if (off->vbase_descr >= 0)
|
||||
{
|
||||
/* move this ptr to vbase descriptor */
|
||||
this_ptr = (char *)this_ptr + off->vbase_descr;
|
||||
/* and fetch additional offset from vbase descriptor */
|
||||
offset_ptr = (int *)(*(char **)this_ptr + off->vbase_offset);
|
||||
this_ptr = (char *)this_ptr + *offset_ptr;
|
||||
}
|
||||
return this_ptr;
|
||||
}
|
||||
|
||||
#endif /* __MSVCRT_CPPEXCEPT_H */
|
||||
|
|
Loading…
Reference in New Issue