Piotr Caban : msvcrt: Support 64-bit RTTI in __RTDynamicCast.

Alexandre Julliard julliard at winehq.org
Wed Sep 5 15:36:45 CDT 2012


Module: wine
Branch: master
Commit: 33937f039f837e3328359d1c617b1424ce334b24
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=33937f039f837e3328359d1c617b1424ce334b24

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Wed Sep  5 14:35:56 2012 +0200

msvcrt: Support 64-bit RTTI in __RTDynamicCast.

---

 dlls/msvcrt/cpp.c       |  113 +++++++++++++++++++++++++++++++++++++++++++++++
 dlls/msvcrt/tests/cpp.c |   27 +++++++++++
 2 files changed, 140 insertions(+), 0 deletions(-)

diff --git a/dlls/msvcrt/cpp.c b/dlls/msvcrt/cpp.c
index b1512f5..81f1d23 100644
--- a/dlls/msvcrt/cpp.c
+++ b/dlls/msvcrt/cpp.c
@@ -117,6 +117,37 @@ static void dump_obj_locator( const rtti_object_locator *ptr )
     }
 }
 
+#ifdef __x86_64__
+static void dump_obj_locator_x64( const rtti_object_locator_x64 *ptr )
+{
+    int i;
+    char *base = (char*)ptr - ptr->object_locator;
+    const rtti_object_hierarchy_x64 *h = (const rtti_object_hierarchy_x64*)(base + ptr->type_hierarchy);
+    const type_info *type_descriptor = (const type_info*)(base + ptr->type_descriptor);
+
+    TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n",
+            ptr, ptr->signature, ptr->base_class_offset, ptr->flags,
+            type_descriptor, dbgstr_type_info(type_descriptor), h );
+    TRACE( "  hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n",
+            h->signature, h->attributes, h->array_len, base + h->base_classes );
+    for (i = 0; i < h->array_len; i++)
+    {
+        const rtti_base_descriptor_x64 *bases = (rtti_base_descriptor_x64*)(base +
+                ((const rtti_base_array_x64*)(base + h->base_classes))->bases[i]);
+
+        TRACE( "    base class %p: num %d off %d,%d,%d attr %08x type %p %s\n",
+                bases,
+                bases->num_base_classes,
+                bases->offsets.this_offset,
+                bases->offsets.vbase_descr,
+                bases->offsets.vbase_offset,
+                bases->attributes,
+                base + bases->type_descriptor,
+                dbgstr_type_info((const type_info*)(base + bases->type_descriptor)) );
+    }
+}
+#endif
+
 /* Internal common ctor for exception */
 static void EXCEPTION_ctor(exception *_this, const char** name)
 {
@@ -919,6 +950,7 @@ const type_info* CDECL MSVCRT___RTtypeid(void *cppobj)
  *  This function is usually called by compiler generated code as a result
  *  of using one of the C++ dynamic cast statements.
  */
+#ifndef __x86_64__
 void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
                                    type_info *src, type_info *dst,
                                    int do_throw)
@@ -982,6 +1014,87 @@ void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
     return ret;
 }
 
+#else
+
+void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
+        type_info *src, type_info *dst,
+        int do_throw)
+{
+    void *ret;
+
+    if (!cppobj) return NULL;
+
+    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);
+
+    __TRY
+    {
+        int i;
+        const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
+
+        if(obj_locator->signature == 0)
+        {
+            const rtti_object_hierarchy *obj_bases = obj_locator->type_hierarchy;
+            const rtti_base_descriptor * const* base_desc = obj_bases->base_classes->bases;
+
+            if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator);
+
+            ret = NULL;
+            for (i = 0; i < obj_bases->array_len; i++)
+            {
+                const type_info *typ = base_desc[i]->type_descriptor;
+
+                if (!strcmp(typ->mangled, dst->mangled))
+                {
+                    void *this_ptr = (char *)cppobj - obj_locator->base_class_offset;
+                    ret = get_this_pointer( &base_desc[i]->offsets, this_ptr );
+                    break;
+                }
+            }
+        }
+        else
+        {
+            const rtti_object_locator_x64 *obj_locator_x64 = (const rtti_object_locator_x64*)obj_locator;
+            const char *base = (const char*)obj_locator_x64 - obj_locator_x64->object_locator;
+            const rtti_object_hierarchy_x64 *obj_bases = (const rtti_object_hierarchy_x64*)(base + obj_locator_x64->type_hierarchy);
+            const rtti_base_array_x64 *base_array = (const rtti_base_array_x64*)(base + obj_bases->base_classes);
+
+            if (TRACE_ON(msvcrt)) dump_obj_locator_x64(obj_locator_x64);
+
+            ret = NULL;
+            for (i = 0; i < obj_bases->array_len; i++)
+            {
+                const rtti_base_descriptor_x64 *base_desc = (const rtti_base_descriptor_x64*)(base + base_array->bases[i]);
+                const type_info *typ = (const type_info*)(base + base_desc->type_descriptor);
+
+                if (!strcmp(typ->mangled, dst->mangled))
+                {
+                    void *this_ptr = (char *)cppobj - obj_locator_x64->base_class_offset;
+                    ret = get_this_pointer( &base_desc->offsets, this_ptr );
+                    break;
+                }
+            }
+        }
+        if (!ret && do_throw)
+        {
+            const char *msg = "Bad dynamic_cast!";
+            bad_cast e;
+            MSVCRT_bad_cast_ctor( &e, &msg );
+            _CxxThrowException( &e, &bad_cast_exception_type );
+        }
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        __non_rtti_object e;
+        MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
+        _CxxThrowException( &e, &bad_typeid_exception_type );
+        return NULL;
+    }
+    __ENDTRY
+    return ret;
+}
+#endif
+
 
 /******************************************************************
  *		__RTCastToVoid (MSVCRT.@)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c
index ddfb922..b3dafbb 100644
--- a/dlls/msvcrt/tests/cpp.c
+++ b/dlls/msvcrt/tests/cpp.c
@@ -881,9 +881,17 @@ static void test_rtti(void)
     { {RTTI_REF(simple_class_rtti, base_descriptor[0])} },
     {0, 0, 1, RTTI_REF(simple_class_rtti, base_array)},
     {RTTI_SIGNATURE, 0, 0, RTTI_REF(simple_class_rtti, type_info[0]), RTTI_REF(simple_class_rtti, object_hierarchy), RTTI_REF(simple_class_rtti, object_locator)}
+  }, child_class_rtti = {
+    { {NULL, NULL, "simple_class"}, {NULL, NULL, "child_class"} },
+    { {RTTI_REF(child_class_rtti, type_info[1]), 0, {4, -1, 0}, 0}, {RTTI_REF(child_class_rtti, type_info[0]), 0, {8, -1, 0}, 0} },
+    { {RTTI_REF(child_class_rtti, base_descriptor[0]), RTTI_REF(child_class_rtti, base_descriptor[1])} },
+    {0, 0, 2, RTTI_REF(child_class_rtti, base_array)},
+    {RTTI_SIGNATURE, 0, 0, RTTI_REF(child_class_rtti, type_info[1]), RTTI_REF(child_class_rtti, object_hierarchy), RTTI_REF(child_class_rtti, object_locator)}
   };
   void *simple_class_vtbl[2] = {&simple_class_rtti.object_locator};
   void *simple_class = &simple_class_vtbl[1];
+  void *child_class_vtbl[2] = {&child_class_rtti.object_locator};
+  void *child_class = &child_class_vtbl[1];
 
   static const char* e_name = "name";
   type_info *ti,*bti;
@@ -923,6 +931,25 @@ static void test_rtti(void)
   ti = p__RTtypeid(&simple_class);
   ok (ti && ti->mangled && !strcmp(ti->mangled, "simple_class"),
           "incorrect rtti data\n");
+
+  casted = p__RTCastToVoid(&simple_class);
+  ok (casted == (void*)&simple_class, "failed cast to void\n");
+
+  ti = p__RTtypeid(&child_class);
+  ok (ti && ti->mangled && !strcmp(ti->mangled, "child_class"),
+        "incorrect rtti data\n");
+
+  casted = p__RTCastToVoid(&child_class);
+  ok (casted == (void*)&child_class, "failed cast to void\n");
+
+  casted = p__RTDynamicCast(&child_class, 0, NULL, simple_class_rtti.type_info, 0);
+  if(casted)
+  {
+    ok (casted == (char*)&child_class+8, "failed cast to simple_class (%p %p)\n", casted, &child_class);
+  }
+
+  casted = p__RTDynamicCast(&child_class, 0, &child_class_rtti.type_info[0], &child_class_rtti.type_info[1], 0);
+  ok(casted == (char*)&child_class+4, "failed cast to child class (%p %p)\n", casted, &child_class);
 }
 
 struct _demangle {




More information about the wine-cvs mailing list