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
source to share
No one has answered this question yet
Check out similar questions: