MSVC: Covariant Return Types and Virtual Inheritance

I'm not sure if this is a bug in the visual-C ++ compiler or undefined.

Setting up

struct DummyBase { virtual ~DummyBase() = default; };
struct DummyDerived : virtual public DummyBase {};

      

Simple class and derived class using virtual inheritance

DummyDerived derived;
DummyBase* base = &derived;

std::cout << "Derived : " << &derived << std::endl;
std::cout << "Base    : " << base << std::endl;

      

When dropped DummyDerived*

before, the DummyBase*

pointer is displaced. This appears to be caused by virtual inheritance:

Derived : 00000000002CF838
Base    : 00000000002CF840

      

Even if the pointer values ​​are different, the comparison will return true:

std::cout << "IsSame  : " << (base == &derived) << std::endl << std::endl;

      

Output:

IsSame  : 1

      

So far so good.

Problem

The problem occurs in the following setting:

 struct IBaseReturner
 {
   virtual DummyBase* Get() = 0;
 };

 struct IDerivedReturner : public virtual IBaseReturner
 {
   virtual DummyDerived* Get() = 0;
 };

 struct BaseReturner : public virtual IBaseReturner
 {
 };

 struct DerivedReturner : public BaseReturner, public virtual IDerivedReturner
 {
   DummyDerived* Ptr;
   virtual DummyDerived* Get() override { return Ptr; }
 };

      

Here we have interfaces and class implementations with methods that either return DummyBase

or DummyDerived

are overwritten with covariant return types. Again with virtual inheritance.

// Setup
DerivedReturner returner;
returner.Ptr = &derived;
IBaseReturner* baseReturner = &returner;

      

Now, return DummyDerived*

from DerivedReturner

and DummyBase*

from the same receiver passed to IBaseReturner

:

DummyDerived* derivedOriginal = returner.Get();
DummyBase* baseFromInterface = baseReturner->Get();

      

Compare Like previous:

std::cout << "Derived Original    : " << derivedOriginal << std::endl;
std::cout << "Base from Interface : " << baseFromInterface << std::endl;

      

Output

Derived Original    : 00000000002CF838
Base from Interface : 00000000002CF838

      

Unlike above, pointers ONLY have a value. Now compare them:

std::cout << "IsSame  : " << (baseFromInterface == derivedOriginal) << std::endl;

      

Output:

IsSame  : 0

      

Comparison false

even returns hard addresses of the same. This is expected because the pointer to DummyBase

must have a different value. Also when trying dynamic_cast:

std::cout << dynamic_cast<DummyDerived*>(baseFromInterface);

      

And the leak is thrown:

unknown file: error: C++ exception with description "Access violation - no RTTI data!" thrown in the test body.

      

Obviously, because the pointer was misplaced.

Conclusion

It seems that when called IBaseReturner::Get

, the visual-C ++ compiler does not do the necessary pointer arithmetic to cast DummyDerived*

into DummyBase*

. This happens in vs2013 and vs2015 (haven't tried another version). Also when compiled with gcc it works fine.

Question

While the installation can be a little tricky, the question is pretty simple:

Is this a msvc bug or am I calling undefined behavoiur?

Added online example: http://rextester.com/KHZXGQ27304

+3


source to share





All Articles