On 11/16/20 9:41 PM, Martin Sebor wrote:
The result of DECL_SIZE_UNIT doesn't always reflect the size
of data members of virtual classes. This can lead to objects
of such types appearing smaller than they are to warnings like
-Warray-bounds or -Wstringop-overflow, causing false positives.
To avoid these false positives, the attached replaces the use
of DECL_SIZE_UNIT in component_ref_size in the middle end with
TYPE_SIZE_UNIT.
Unfortunately, that's not enough; the offset between the intermediate
base and the virtual base could be greater than the TYPE_SIZE of the
intermediate base:
extern "C" int printf (const char *, ...);
struct A { char ar1[24]; };
struct B: virtual A { };
struct C { char ar2[42]; };
struct D: B, C { };
int main()
{
D d;
printf ("size %d, offset %d\n", sizeof (B), d.ar1 - (char*)(B*)&d);
}
Here base C is allocated between base B and its virtual base A, so the
offset between them is 50, while the size of B is only 32.
The difference between TYPE_SIZE and DECL_SIZE could be a way to
recognize the case of bases with virtual bases, and then either hunt
down all the virtual bases or just use the bounds of the enclosing
most-derived object.
+ /* DECL_SIZE may be less than TYPE_SIZE in C++ when referring
+ to the type of a virtual base class which doesn't reflect
+ the size of the virtual's members (see pr97595). */
The problem isn't with the virtual base class itself (A), but with the
intermediate base class subobject (B), for which DECL_SIZE doesn't
include the size of the virtual base A, because the A base subobject is
allocated separately.
Jason