From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29585 invoked by alias); 27 May 2002 10:36:16 -0000 Mailing-List: contact gcc-prs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-prs-owner@gcc.gnu.org Received: (qmail 29535 invoked by uid 71); 27 May 2002 10:36:05 -0000 Resent-Date: 27 May 2002 10:36:04 -0000 Resent-Message-ID: <20020527103604.29534.qmail@sources.redhat.com> Resent-From: gcc-gnats@gcc.gnu.org (GNATS Filer) Resent-To: nobody@gcc.gnu.org Resent-Cc: gcc-prs@gcc.gnu.org, gcc-bugs@gcc.gnu.org Resent-Reply-To: gcc-gnats@gcc.gnu.org, Grigory_Zagorodnev@vniief.ims.intel.com Received:(qmail 29008 invoked by uid 61); 27 May 2002 10:33:54 -0000 Message-Id:<20020527103352.29003.qmail@sources.redhat.com> Date: Mon, 27 May 2002 04:26:00 -0000 From: Grigory_Zagorodnev@vniief.ims.intel.com Reply-To: Grigory_Zagorodnev@vniief.ims.intel.com To: gcc-gnats@gcc.gnu.org X-Send-Pr-Version:gnatsweb-2.9.3 (1.1.1.1.2.31) Subject: c++/6831: Wrong base class alignment (nvalign vs. align) X-SW-Source: 2002-05/txt/msg00862.txt.bz2 List-Id: >Number: 6831 >Category: c++ >Synopsis: Wrong base class alignment (nvalign vs. align) >Confidential: no >Severity: serious >Priority: medium >Responsible: unassigned >State: open >Class: sw-bug >Submitter-Id: net >Arrival-Date: Mon May 27 03:36:01 PDT 2002 >Closed-Date: >Last-Modified: >Originator: Grigory Zagorodnev >Release: 3.1 >Organization: >Environment: host: ia64-unknown-linux build: ia64-unknown-linux target: ia64-unknown-linux configured with: ./configure >Description: 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. 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. II. 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. III. 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). >How-To-Repeat: 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++ 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 >Fix: >Release-Note: >Audit-Trail: >Unformatted: ----gnatsweb-attachment---- Content-Type: text/plain; name="fail.cpp" Content-Disposition: inline; filename="fail.cpp" #include 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; }; E e; /* 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 */ int main () { // Offset of base class D is expected to be sizeof(void *) size_t d_offset = ((char*) (D*) (&e)) - (char*) &e; if( d_offset != sizeof(void *) ){ puts("failed"); printf("D's offset is %d\nexpected %d\n", d_offset, sizeof(void *)); } else puts("passed"); }