[omniORB] MSVC 6.0 bug with inheritance across namespaces (modules)

Dietmar May dcmay@object-workshops.com
Wed, 29 Jul 1998 08:43:17 -0700


The following documents an apparent bug in Microsoft Visual C++ 5.0 sp3
(other versions haven't been tried) which prevents inheritance in one
module from an interface defined in another module; or more precisely,
causes a run-time error condition which will cause erroneous dispatch
operation when a method defined in the base interface is called on an
instance of the derived interface. 

The generated dispatch() function performs a series of strcmp()
operations. If no match is found, the dispatch function calls the base
class dispatch() function, to permit it to search for a match. However,
the compiler generates code which references (calls) the function
definition in the derived class, rather than in the base class - in
other words, a cyclical reference, which eventually exhausts the stack
and throws an exception.

/*
module X
{
    interface A
    {
        void func ();                  //cannot call this method from
Y::A object type
    };
    interface B : A
    {
        void func ();                  //this is fine - same namespace
as X::A
    };
}

module Y
{
    interface A
    {
        void func2 ();                 //no problem accessing this
    };
}
*/

namespace X
{
    class A
    {
    public:
        virtual void func ();
    };

    class B : public A
    {
    public:
        virtual void func ();
    };
}

namespace Y
{
    class A : public X::A
    {
    public:
        virtual void func ();
        virtual void func2 ();
    };
}

typedef X::A X_A;

void doit ();

void X::A::func ()
{
    doit();
}

void X::B::func ()
{
    X_A::func();                    //this works fine - same namespace
as X::A
    ((X_A*)this)->X_A::func();      //this works fine too - patch works
in all cases
}

void Y::A::func ()
{
    X_A::func();                    //fails - calls Y::A::func()!!
    ((X_A*)this)->X_A::func();      //ugly way to call it, but it
works!! 
}

The MSVC 5.0 compiler generates the following assembly language code:

?func@A@X@@UAEXXZ PROC NEAR                             ; X::A::func
;       ... stack frame setup here
        call    ?doit@@YAXXZ                            ; doit
;       ... stack frame cleanup here
?func@A@X@@UAEXXZ ENDP                                  ; X::A::func

?func@B@X@@UAEXXZ PROC NEAR                             ; X::B::func
;       ... stack frame setup here
        mov     ecx, DWORD PTR _this$[ebp]
        call    ?func@A@X@@UAEXXZ                       ; X::A::func
; 
        mov     ecx, DWORD PTR _this$[ebp]
        call    ?func@A@X@@UAEXXZ                       ; X::A::func
;       ... stack frame cleanup here
?func@B@X@@UAEXXZ ENDP                                  ; X::B::func

?func@A@Y@@UAEXXZ PROC NEAR                             ; Y::A::func
;       ... stack frame setup here

;       X_A::func();                    //fails - calls Y::A::func()!!

        mov     ecx, DWORD PTR _this$[ebp]
        call    ?func@A@Y@@UAEXXZ                       ; OOOOPS!!!
Y::A::func

;      ((X_A*)this)->X_A::func();       //ugly way to call it, but it
works!! 

        mov     ecx, DWORD PTR _this$[ebp]
        call    ?func@A@X@@UAEXXZ                       ; X::A::func
;       ... stack frame cleanup here
?func@A@Y@@UAEXXZ ENDP                                  ; Y::A::func

To fix omniIDL2, patch
omniORB\src\tool\omniidl2\omniORB2_be\o2be_interface.cc line 1586 etc,
and line 1982 etc:

                strcpy(intf_name,intf->_scopename());             //DCM
shown here for context
                strcat(intf_name,intf->lcserver_uqname());        //DCM
shown here for context
              }
            }
          IND(s); s << ((notfirst)?"else ":"")
                    << "if (OMNI_BASE_DISPATCH(" << intf_name
                    << ")(_0RL_s,_0RL_op,_0RL_response_expected)) {\n";

Then, patch omniORB.h (or perhaps another header would be more
appropriate) with:

#if _MSC_VER >= 1100
#define OMNI_BASE_DISPATCH(_base_class)
((_base_class*)this)->_base_class::dispatch
#else
#define OMNI_BASE_DISPATCH(_base_class) _base_class::dispatch
#endif

Regards,
Dietmar May

Software Architect
Object Workshops, Inc.
http://www.object-workshops.com
dcmay@object-workshops.com