[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