C++ Logo


Advanced search

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

From: Herb Sutter <hsutter_at_[hidden]>
Date: Wed, 15 Jan 2014 21:48:26 +0000
Richard, I'm not sure I understand your position... Given the following complete program ...

  struct B { int i; };
  struct D : B { };

  int main() {
    B b; // line X

... are you actually saying that line X starts the lifetime of an object of type D? or just setting up a strawman? (Sorry, I really couldn't tell.)

If yes, then given the following complete program ...

  struct C { long long i; };

  int main() {
    C c; // line Y

... are you saying that line Y could start the lifetime of an object of type D (which is not mentioned in the code), double, shared_ptr<widget>, or any other type than C, as long as the size of that other type is the same or less than sizeof(C)?


From: ub-bounces_at_[hidden] <ub-bounces_at_[hidden]> on behalf of Richard Smith <richardsmith_at_[hidden]>
Sent: Monday, January 6, 2014 3:44 PM
To: WG21 UB study group
Subject: Re: [ub] type punning through congruent base class?

On Mon, Jan 6, 2014 at 10:22 AM, Jason Merrill <jason_at_[hidden]<mailto: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;

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));

... so any counterargument will need to explain why the two cases are fundamentally different.)



... 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-15 23:03:26