cplusplus / CWG

Core Working Group
23 stars 7 forks source link

CWG2897 [class.copy.ctor, class.copy.assign] Copying object representation may be problematic for potentially-overlapping union subobjects #542

Open frederick-vs-ja opened 4 months ago

frederick-vs-ja commented 4 months ago

Full name of submitter (unless configured in github; will be published with the issue): Jiang An

Reference (section label): [class.copy.ctor], [class.copy.assign]

Link to reflector thread (if any):

Issue description:

It's specified in [class.copy.ctor] p15 and [class.copy.assign] p13 that a trivial and elegible copy or move function of a union copies the object representation, which can be problematic when the union object is a potentially-overlapping member subobject, and another subobject of the complete object overlaps with its tail padding, because the latter will be unintentionally overwritten.

Suggested resolution:

Change [class.copy.ctor] p15 as indicated:

The implicitly-defined copy/move constructor for a union X copies the ~object~ value representation ([basic.types.general]) of X. [...]

Change [class.copy.assign] p13 as indicated:

The implicitly-defined copy/move assignment operator for a union X copies the ~object~ value representation ([basic.types.general]) of X. [...]

jensmaurer commented 4 months ago

We copy subobjects in order, so we would first copy the object representation of the union and then copy the object that lives in the tail padding. Where is the problem?

frederick-vs-ja commented 4 months ago

I think a virtual base class subobject may be incorrectly overwritten in construction. It's initialized earlier than any member subobject, however, at least on Itanium ABI, it may live in the padding of a member subobject.

t3nsor commented 4 months ago

We copy subobjects in order, so we would first copy the object representation of the union and then copy the object that lives in the tail padding. Where is the problem?

What about

union U {};
struct S {
    U u [[no_unique_address]];
    char c;
};
S s;
s.c = 1;
s.u = U();

My understanding was that the issue has to do with a situation like this. The call to U's move assignment operator might disturb the value of s.c.

t3nsor commented 4 months ago

Also, suppose we exchanged the order of the members:

struct S {
    char c;
    U u [[no_unique_address]];
};

It's still possible that an implementation allocates c and u at the same byte of S.

jensmaurer commented 4 months ago

CWG2897