C++ Logo

sg12

Advanced search

Re: [ub] type punning through congruent base class?

From: Richard Smith <richardsmith_at_[hidden]>
Date: Mon, 6 Jan 2014 15:44:29 -0800
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'. 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).

Received on 2014-01-12 04:28:07