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:
Alexandre Julliard 2004-10-18 23:13:55 +00:00
parent e62e88f488
commit b8d5d962ee
3 changed files with 95 additions and 75 deletions

View File

@ -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++;

View File

@ -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 );
}
}

View File

@ -84,14 +84,20 @@ typedef struct __cxx_function_descr
typedef void (*cxx_copy_ctor)(void);
/* offsets for computing the this pointer */
typedef struct
{
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 */
} 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 */
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 */
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;
@ -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 */