Dynamic cast bug with multiple inheritance

From: Juan Esteban Bernabó (jbernab_at_ig.com.br)
Date: 03/09/04


Date: Mon, 8 Mar 2004 16:06:07 -0800


/**
 * This are two test cases to show a probable bug on the VC++ compiler or rt.
 *
 * A __non_rtti_object exception is throw when tried to dynamically downcast
 * from a base virtual class to a derived class from a method called from a
 * base class constructor. The funny thing is that if the concrete class has
 * a "long" attribute on its body it shows this behavior if it doesn´t the code
 * works clean.
 *
 * This probably is a bug in the compiler or the runtime library but I first
 * experienced it in VC++ 6.0 SP5 and installed VC++ .NET to try and ocurred the
 * same thing.
 * @author Juan Esteban Bernabó (jbernab@ig.com.br)
 */

/**
 * If you have the CPPUNIT framework uncomment this otherwise compile this with
 * the HAVE_CPPUNIT macro undefined
 */
//#define HAVE_CPPUNIT 1
#undef HAVE_CPPUNIT

#ifdef HAVE_CPPUNIT
#include <cppunit/extensions/HelperMacros.h>
#endif

#include <iostream>

class TestVC
#ifdef HAVE_CPPUNIT
        : public CppUnit::TestFixture
#endif
{
#ifdef HAVE_CPPUNIT
        CPPUNIT_TEST_SUITE( TestVC );
        CPPUNIT_TEST( testVC1 );
        CPPUNIT_TEST_EXCEPTION( testVC2, bad_typeid );
        CPPUNIT_TEST_SUITE_END();
#endif

public :

        /**
         * This is kind of a class hierarchy tree.
         * Reference
         * Object Interface
         * Runnable
         * Thread
         * W X
         **/

        class Reference
        {
                virtual void testRe() { };
        };

        class Interface : virtual public Reference
        {
                virtual void testI() { };
        };
        
        class Object : virtual public Reference
        {
                virtual void testO() { };
        };

        class Runnable : virtual public Interface
        {
                virtual void testR() { };
        };

        class Thread : public Object, virtual public Runnable
        {
        public:
                Thread( )
                {
                        setReference( this );
                }

                void setReference( Reference *that )
                {
                        Runnable *r = dynamic_cast<Runnable*>( that );
                }
        };

        class W : public Thread
        {
        public:
                W() : Thread( ) { }
                long teste;
        };

        class X : public Thread
        {
        public:
                X() : Thread( ) { }
// With this commented out the bug comes to live
// long teste;
        };

        /**
         * The VC bug manifest when you try to dynamic_cast an object that is been
         * constructed and has a long attribute, that's the way I reproduced this bug
         * but probably there should be others.
         **/
        void testVC2()
        {
                W w;
        }

        /**
         * With the X class the problem doensn't happen as it has the "test" attibute
         * commented out.
         */
        void testVC1()
        {
                X x;
        }

};

/** If you dont have CPPUNIT */
#ifndef HAVE_CPPUNIT
extern "C" int main()
{
        TestVC t;

        try
        {
                t.testVC1();
                std::cout << "t.testVC1() = OK" << std::endl;
        } catch( exception &e )
        {
                std::cout << "t.testVC2() = " << e.what() << std::endl;
        }

        try
        {
                t.testVC2();
                std::cout << "t.testVC2() = OK" << std::endl;
        } catch( exception &e )
        {
                std::cout << "t.testVC2() = " << e.what() << std::endl;
        }
        return 0;
}
#endif

#ifdef HAVE_CPPUNIT
CPPUNIT_TEST_SUITE_REGISTRATION( TestVC );
#endif



Relevant Pages