Bug 65210 - Wrong base class alignment (nvalign vs. align)
Summary: Wrong base class alignment (nvalign vs. align)
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: gcc3
Version: 7.2
Hardware: ia64
OS: Linux
medium
high
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2002-05-20 11:56 UTC by Grigory Zagorodnev
Modified: 2007-04-18 16:42 UTC (History)
0 users

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2004-10-02 20:36:15 UTC
Embargoed:


Attachments (Terms of Use)
The testcase (836 bytes, text/plain)
2002-05-20 11:57 UTC, Grigory Zagorodnev
no flags Details

Description Grigory Zagorodnev 2002-05-20 11:56:00 UTC
From Bugzilla Helper:
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; NetCaptor 
6.5.0PB8)

Description of problem:
G++3 gives wrong layout of class E object in the testcase below.

1. The testcase
---------------
struct A {
    int a;
};

struct B : public virtual A {};

struct C {
  long double c;
};

struct D : public virtual C {
    int d;
};

struct E : public B, public D {
    int e;
};


2. The issue
------------
Expected layout of class E on ia64 is the following:
    Offset Size	Contents
    [0000] 8	B's virtual table pointer (B is the primary base for E)
    [0008] 8	D's virtual table pointer
    [0010] 4	D::d
    [0014] 4	Padding to round up D size to multiple of pointer align (8)
    [0018] 4	E::e
    [001c] 4	A::a
    [0020] 16	C::c

But G++3 compiler gives another object layout for E:
    Offset Size	Contents
    [0000] 8	B's virtual table pointer (B is the primary base for E)
    [0008] 8	Padding 
    [0010] 8	D's virtual table pointer
    [0018] 4	D::d
    [001c] 4	E::e
    [0020] 4	A::a
    [0024] 12	Padding
    [0030] 16	C::c

The layout is different and is wrong.

3. Details and analisis
-----------------------
We see difference in three points here, all related to padding bytes added.

I. Padding after B's virtual table pointer
This is the major inconsistency. Let's see...

The C++ ABI says [Chapter 2: Data Layout/2.4 Non-POD Class Types/II. Allocation 
of Members Other Than Virtual Bases]:
"if D is not an empty base class (including all data members), start at offset 
dsize(C), incremented if necessary for alignment to nvalign(type(D)) for base 
classes or to align(type(D)) for data members. "

In our case, nvalign(D) == 8, align(D) == 16. 
So, it looks like g++3 did increment address to keep 16-bytes alignment of 
class D. But this is valid for data members only and not for base classes. Such 
behaviour is wrong. Since D is the base class, it should be aligned to nvalign
(D)==8 bytes within class E and there should not be any padding.

In other words, g++3 erroneously uses align(D) instead of nvalign(D).

II. No padding after D::d
Class D is laying out using common rules. It means that D should be finalized 
either - rounded up to a non-zero multiple of align(D). 
g++3 does not perform this step for base classes. See Bugzilla Bug #64535 for 
details.


III. Extra padding after A::a
There is nothing wrong - C::c should be 16-byte aligned.
Difference is just a side-effect of inconsistency listed above.


Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
It's not so easy to dump object as showed above. So we are using run-time test 
which checks offset of class D within the object E. It used to be sizeof(void 
*), i.e. D is comming right after class B, when B contains only the virtual 
table pointer.

1. Build attached fail.cpp test using simple command line
     g++3 fail.cpp
2. Run it
     ./a.out
3. Look for 'passed' word in the output


Actual Results:  failed
D's offset is 16
expected 8


Expected Results:  passed

Additional info:

Comment 1 Grigory Zagorodnev 2002-05-20 11:57:02 UTC
Created attachment 58005 [details]
The testcase

Comment 2 Alan Cox 2002-12-15 20:32:24 UTC
Ok with g++ 3.2 on x86 at least


Comment 3 Richard Henderson 2004-10-02 20:36:15 UTC
The given test case does pass with gcc 3.2, though the layout is
slightly different than described.  It's

[000] vptr for B
[008] vptr for D
[010] D::d
[014] E::e
[018] A::a
[020] C::c

I.e. E is using the tail padding in D.  I don't see anything wrong
with this.


Note You need to log in before you can comment on or make changes to this bug.