Bug 37762 - Member variable of empty base optimized (EBO) class appears on wrong offset
Summary: Member variable of empty base optimized (EBO) class appears on wrong offset
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.3.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-10-07 08:40 UTC by David Rosenborg
Modified: 2008-10-07 09:48 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Preprocessed program (4.55 KB, text/plain)
2008-10-07 08:42 UTC, David Rosenborg
Details

Note You need to log in before you can comment on or make changes to this bug.
Description David Rosenborg 2008-10-07 08:40:32 UTC
A member variable of a class that utilizes EBO and has a type that also utilizes EBO appears to be laid out at the wrong offset.

In the example below, the only difference between the classes Good and Bad is that the member of Bad inherits from a class with no members. The sizeof printouts show that EBO is in play, but the Bad class gets an extra four byte padding before the member. There's no reason Bad should be any larger than Good.

Kind Regards
/David

#include <cstdio>

struct Empty { };

struct Member { int extent; };
struct MemberWithEBO : public Empty { int extent; };

struct Good : public Empty { Member m; }; // OK
struct Bad : public Empty { MemberWithEBO m; }; // Broken, see below

#define PRINT(x) printf ("%-25s %d\n", # x ":", (x))

template <typename C, typename T> long int offsetOf (T C::*m)
{
   C proto;
   return (long int)(void*)&(proto.*m) - (long int)(void *)&proto;
}

int
main (int argc, char ** argv)
{
   PRINT (sizeof (Member));
   PRINT (sizeof (Good));
   PRINT (offsetOf (&Good::m));

   PRINT (sizeof (MemberWithEBO));
   PRINT (sizeof (Bad));
   PRINT (offsetOf (&Bad::m));
}

// Printout:
//
// sizeof (Member):          4
// sizeof (Good):            4
// offsetOf (&Good::m):      0
// sizeof (MemberWithEBO):   4
// sizeof (Bad):             8  <-- Should be 4
// offsetOf (&Bad::m):       4  <-- Should be 0




> g++ -v -save-temps ebo_bug.cc

Using built-in specs.
Target: x86_64-unknown-linux-gnu
Configured with: ../configure --prefix=/usr/local/gcc431 --with-pkgversion=gcc431 --enable-languages=c,c++
Thread model: posix
gcc version 4.3.1 (gcc431) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
 /usr/local/gcc431/libexec/gcc/x86_64-unknown-linux-gnu/4.3.1/cc1plus -E -quiet -v -D_GNU_SOURCE ebo_bug.cc -mtune=generic -fpch-preprocess -o ebo_bug.ii
ignoring nonexistent directory "/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../../x86_64-unknown-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../../include/c++/4.3.1
 /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../../include/c++/4.3.1/x86_64-unknown-linux-gnu
 /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../../include/c++/4.3.1/backward
 /usr/local/include
 /usr/local/gcc431/include
 /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/include
 /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
 /usr/local/gcc431/libexec/gcc/x86_64-unknown-linux-gnu/4.3.1/cc1plus -fpreprocessed ebo_bug.ii -quiet -dumpbase ebo_bug.cc -mtune=generic -auxbase ebo_bug -version -o ebo_bug.s
GNU C++ (gcc431) version 4.3.1 (x86_64-unknown-linux-gnu)
        compiled by GNU C version 4.3.1, GMP version 4.1.4, MPFR version 2.2.1.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 4926fc16e15403c044148a60354159ba
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
 as -V -Qy -o ebo_bug.o ebo_bug.s
GNU assembler version 2.17.50.0.6-6.el5 (x86_64-redhat-linux) using BFD version 2.17.50.0.6-6.el5 20061020
COMPILER_PATH=/usr/local/gcc431/libexec/gcc/x86_64-unknown-linux-gnu/4.3.1/:/usr/local/gcc431/libexec/gcc/x86_64-unknown-linux-gnu/4.3.1/:/usr/local/gcc431/libexec/gcc/x86_64-unknown-linux-gnu/:/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/:/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/
LIBRARY_PATH=/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/:/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
 /usr/local/gcc431/libexec/gcc/x86_64-unknown-linux-gnu/4.3.1/collect2 --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/../lib64/crt1.o /usr/lib/../lib64/crti.o /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/crtbegin.o -L/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1 -L/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/../../.. ebo_bug.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/gcc431/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/crtend.o /usr/lib/../lib64/crtn.o
Comment 1 David Rosenborg 2008-10-07 08:42:08 UTC
Created attachment 16474 [details]
Preprocessed program
Comment 2 Paolo Carlini 2008-10-07 08:46:25 UTC
Do you have evidence that this is a bug given the detailed specifications of the ABI document:

  http://www.codesourcery.com/public/cxx-abi/

???

I have trouble believing it, and just checked that other compilers conforming to the multi-vendor standard ABI behave exactly the same as GCC...
Comment 3 David Rosenborg 2008-10-07 09:31:12 UTC
Ah, no, I wasn't aware of that document. I just thought that gcc was treating the Good and Bad cases inconsitently.

Now, in layman's terms, is the reason for the padding that no two distinct instances of Empty may share the same address? If that is the case, it would explain the padding and this is not a bug.

Sorry, should have investigated more before hitting the commit button.

/David
Comment 4 Paolo Carlini 2008-10-07 09:48:32 UTC
(In reply to comment #3)
> Now, in layman's terms, is the reason for the padding that no two distinct
> instances of Empty may share the same address? If that is the case, it would
> explain the padding and this is not a bug.

Yes, that is a very basic requirement that EBO cannot circumvent. About layman' explanations of the basic logic, I suggest paragraph 16.2 of "C++ Templates: The Complete Guide".
Comment 5 pinskia@gmail.com 2008-10-07 10:45:47 UTC
Subject: Re:  Member variable of empty base optimized (EBO) class appears on wrong offset

Iirc there are some pod vs non pod issues here dealing wit padding and  
the c++ standard and not even the abi.

Sent from my iPhone

On Oct 7, 2008, at 2:31 AM, "david dot rosenborg at pantor dot com" <gcc-bugzilla@gcc.gnu.org 
 > wrote:

>
>
> ------- Comment #3 from david dot rosenborg at pantor dot com   
> 2008-10-07 09:31 -------
> Ah, no, I wasn't aware of that document. I just thought that gcc was  
> treating
> the Good and Bad cases inconsitently.
>
> Now, in layman's terms, is the reason for the padding that no two  
> distinct
> instances of Empty may share the same address? If that is the case,  
> it would
> explain the padding and this is not a bug.
>
> Sorry, should have investigated more before hitting the commit button.
>
> /David
>
>
> -- 
>
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37762
>