C++ + gcc: tail padding reuse and PODs
Asked Answered
M

1

5

Related question: Standard-layout and tail padding

Snippet:

#include <iostream>
#include <type_traits>

struct A0
{
    int a;
    char c;
};

struct B0 : A0
{ char d; };

struct A1
{
    int a;

private:
    char c;
};

struct B1 : A1
{ char d; };

struct A2
{
private:
    int a;
    char c;
};

struct B2 : A2
{ char d; };

int main()
{
    std::cout << std::is_pod<A0>::value << ' ' << sizeof(B0) << std::endl; // 1 12
    std::cout << std::is_pod<A1>::value << ' ' << sizeof(B1) << std::endl; // 0 8
    std::cout << std::is_pod<A2>::value << ' ' << sizeof(B2) << std::endl; // 1 8
}

Live demo // Using g++

It's usually said that, when you inherit from a POD type with tail padding, for some historical reasons, the Itanium ABI (that honestly, I don't know what that is) doesn't allow to reause tail padding of a base-class subobject if such subobject is POD.

However, in the third case, A2 is POD because all of its members have the same access control, but B2 is reusing such tail padding. Why is that?

Marjorymarjy answered 1/5, 2020 at 18:7 Comment(5)
There are no such special rules for inheriting from a POD (or whatever this week's term is), neither in the C++ standard nor in Itanium ABI. А class can reuse holes in its potentially-overlapping subobject (which B2::A2 is), unless the class itself is a POD (which B2 is not).Justness
@n.'pronouns'm. This is what I refer: #53837873Marjorymarjy
The question you link demonstrates that padding can be reused. Why do you think it cannot?Justness
@n.'pronouns'm. Can be reused when the class-base subobject is non-POD, however, in my third case the subobject is a POD and the padding has been reused anyway. So, what's the real restriction here? Although I think you answered already my question when you said that the class itself (not the base-class, but the derived class) is non-POD.Marjorymarjy
note that is_pod will be removed in C++20, consider using is_standard_layoutDispersant
J
7

The current standard always allows alignment tail holes to be reused in any base class subobject. It doesn't have to be a "POD" (or a modern-day equivalent, "trivially copyable"). Indeed, any base class subobject is a "potentially-overlapping subobject", and "potentially-overlapping subobjects" are not memcpy-able.

The Itanium ABI doesn't keep track of what is or is not a POD or equivalent in the current standard. It allows (mandates, in fact) alignment tail holes to be reused in any base subobject which is not a POD according to the C++98 definition.

1.1 Definitions:

This ABI uses the definition of POD only to decide whether to allocate objects in the tail-padding of a base-class subobject. While the standards have broadened the definition of POD over time, they have also forbidden the programmer from directly reading or writing the underlying bytes of a base-class subobject with, say, memcpy. Therefore, even in the most conservative interpretation, implementations may freely allocate objects in the tail padding of any class which would not have been POD in C++98. This ABI is in compliance with that.

In C++98, A2 would not have been a POD because it has private members. So GCC reuses the tail padding according to the ABI, and in compliance with the current standard or any previous standard back to C++98.

Justness answered 2/5, 2020 at 10:25 Comment(10)
Can you provide any quotes from the standard to support the claim of your first sentence? Does this apply to any holes or only tail holes?Dispersant
@Dispersant this answer seems to have some of the relevant quotes #52884757 If you search for "potentially-overlapped subobject" you'll find everything. I think this applies to all holes, but Itanium ABI only reuses tail holes (but don't quote me on that).Justness
That question talks about placement-new (ending the lifetime of a subobject seems to be a different case to modifying some bytes of it)Dispersant
You cannot reuse a potentially-overlapped subobject or memcpy to a potentially-overlapped subobject because of the same issue. There might be something inside its memory that belongs to a different object and you would thrash it.Justness
The quotes in the linked answer only apply to "after the lifetime of an object has ended and before the storage which the object occupied is reused or released" which is not the case for using "active" tail padding for extra objectsDispersant
Can you just search the standard for "potentially-overlapped subobject"?Justness
That term does not occur in the standardDispersant
potentially-overlapping, sorryJustness
That's not in the current standard either (it is in C++20 drafts)Dispersant
You are right, in the current standards there is no no_­unique_­address attribute, so only base classes may overlap. AFAICT the exact same things which are true about potentially-overlapping subobjects in the draft are true about base class subobjects in the current standard (you cannot reuse or memcpy them).Justness

© 2022 - 2024 — McMap. All rights reserved.