Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inspecting non-active union members, common initial sequence

Tags:

This question is based on this

Consider the following:

struct Hdr { int type; };
struct A { Hdr h; };
union Big {
   Hdr h;
   A a;
};

and suppose that for Big big we know that big.a is the active member of the union. Is the access to big.h.type undefined behavior?

I think is indeed UB, based on:

class.union

... [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence ([class.mem]), and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of the standard-layout struct members; see [class.mem]. — end note ]

We have a standard layout union which has standard layout member structs but as understand it, the common initial sequence for Hdr and A is empty even though the first data member of A is of type of Hdr.

Am I right in that this is UB ? if not, which point of common initial sequence I misunderstood so that the access big.h.type is defined ?

like image 267
xeros Avatar asked Feb 05 '19 01:02

xeros


1 Answers

I see no fault in your interpretation.

As per your quote, this is well defined only if A and Hdr share a common initial sequence that includes Hdr::type.

To quote the rule that defines the common initial sequence:

[class.mem] The common initial sequence of two standard-layout struct ([class.prop]) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types ...

So, the first members of A and Hdr are common if they - that is int and Hdr - are layout-compatible types. That is specified in

[basic.types] Two types cv1 T1 and cv2 T2 are layout-compatible types if T1 and T2 are the same type (they are not the same type), layout-compatible enumerations (they are not enumerations), or layout-compatible standard-layout class types (only one of them is a class type).

As none apply, int and Hdr are not layout-compatible, and therefore the common initial sequence of A and Hdr is empty and therefore there is no member to which the quoted special guarantee applies.


You could use a wrapper to get around the subtlety of the rule:

union Big {
   struct {
       Hdr h;
   } w;
   A a;
} big;

Here, accessing big.w.h.type would be well defined even if big.a is active. P.S. Anonymous struct would be nice here to make the wrapper invisible. Unfortunately those are ill-formed in standard C++.

like image 125
eerorika Avatar answered Jan 04 '23 18:01

eerorika