C++ Logo

SG12

Advanced search

Subject: Re: [ub] type punning through congruent base class?
From: Richard Smith (richardsmith_at_[hidden])
Date: 2014-01-06 17:45:13


On Mon, Jan 6, 2014 at 3:44 PM, Richard Smith <richardsmith_at_[hidden]>wrote:

> On Mon, Jan 6, 2014 at 10:22 AM, Jason Merrill <jason_at_[hidden]> wrote:
>
>> On 01/06/2014 04:26 AM, Fabio Fracassi wrote:
>> > if it is not (legal): could we make it legal or would we run afoul of
>> > the aliasing rules?
>>
>> The access is not allowed by the aliasing rules in 3.10. But it seems
>> that this would be:
>>
>> struct B {
>> int i;
>> };
>>
>> struct D {
>> B bmem;
>> void foo() { /* access bmem.i */ }
>> };
>>
>> B b;
>> reinterpret_cast<D&>(b).foo();
>>
>> because B is a non-static data member of D, and 9.2/19 guarantees that
>> the address of D::bmem is the same as the address of the D object.
>
>
> How is that fundamentally different? 9.3.1/2 makes that UB too, if
> 'reinterpret_cast<D&>(b)' does not refer to an object of type 'b'.
>

... an object of type 'D'. Sorry!

> And within D::foo, the implicit this->bmem would have the same problem.
>
>
> If I might play devil's advocate for a moment...
>
> struct B { int i; };
> struct D : B {
> void foo();
> };
>
> B b;
>
> I claim this line starts the lifetime of an object of type D. Per
> [basic.life]p1, the lifetime of an object of type 'D' begins when storage
> with the proper alignment and size for type T is obtained (which "B b"
> happens to satisfy). The object does not have non-trivial initialization,
> so the second bullet does not apply.
>
> (This is the same argument that makes this valid:
>
> D *p = (D*)malloc(sizeof(D));
> p->foo();
>
> ... so any counterargument will need to explain why the two cases are
> fundamentally different.)
>
> Then:
>
> reinterpret_cast<D&>(b).foo();
>
> ... is valid, because the cast produces the same memory address, and that
> memory address contains an object of type 'D' (as claimed above).
>



SG12 list run by herb.sutter at gmail.com