From b8d5d962eef1042ced9c37f538f1eb9a8099d5d6 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 18 Oct 2004 23:13:55 +0000 Subject: [PATCH] Fixed __RTDynamicCast to return the correct pointer for multiple inheritance hierarchies (thanks to Muse Research for help with this one). Added some debug output. --- dlls/msvcrt/cpp.c | 82 ++++++++++++++++++++++------------------- dlls/msvcrt/cppexcept.c | 44 ++++++---------------- dlls/msvcrt/cppexcept.h | 44 +++++++++++++++++++--- 3 files changed, 95 insertions(+), 75 deletions(-) diff --git a/dlls/msvcrt/cpp.c b/dlls/msvcrt/cpp.c index 9bfd80cb475..808938341d3 100644 --- a/dlls/msvcrt/cpp.c +++ b/dlls/msvcrt/cpp.c @@ -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++; diff --git a/dlls/msvcrt/cppexcept.c b/dlls/msvcrt/cppexcept.c index 54b4f5aedc9..cfe951c20a3 100644 --- a/dlls/msvcrt/cppexcept.c +++ b/dlls/msvcrt/cppexcept.c @@ -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 ); } } diff --git a/dlls/msvcrt/cppexcept.h b/dlls/msvcrt/cppexcept.h index 3a822ed9ec0..c34622bef5c 100644 --- a/dlls/msvcrt/cppexcept.h +++ b/dlls/msvcrt/cppexcept.h @@ -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 */