Bug 52023 - [C11] _Alignof (double) yields wrong value on x86
Summary: [C11] _Alignof (double) yields wrong value on x86
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: 4.9.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-01-27 18:05 UTC by Paul Eggert
Modified: 2022-05-13 01:06 UTC (History)
5 users (show)

See Also:
Host: x86-64
Target: x86
Build: x86-64
Known to work:
Known to fail:
Last reconfirmed: 2012-01-30 00:00:00


Attachments
gcc -v output (867 bytes, text/plain)
2012-01-27 18:05 UTC, Paul Eggert
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Eggert 2012-01-27 18:05:22 UTC
Created attachment 26482 [details]
gcc -v output

On x86, alignof (double) should be 4, since that's the alignment
requirement used for 'double' when laying out structures.  But with
GCC alignof incorrectly returns 8.  This causes some gnulib tests to fail
and (more importantly) it may cause problems with programs such as
conservative garbage collectors that use alignof to determine which
addresses might be of valid objects.

The problem also occurs with other fundamental types, such as 'long long'.

Here's a simple test case:

  #include <stddef.h>
  #include <stdalign.h>
  int a = alignof (double);
  int b = offsetof (struct { char c; double d; }, d);
  int main (void) { return a == b; }

Here's the preprocessed output:

  int a = _Alignof (double);
  int b = __builtin_offsetof (struct { char c; double d; }, d);
  int main (void) { return a == b; }

'main' should return 1, but it returns 0 due to the bug, which causes
'a' to be 8 instead of 4 as it should be.

I'm using GCC on the trunk (r183603), built on Fedora 16 x86-64 with
no special flags, and I'm compiling with 'gcc -v -m32 test.c' and
running with './a.out'.  I'm attaching the output of 'gcc -v'.
Comment 1 Andrew Pinski 2012-01-27 18:49:01 UTC
I don't think this is a bug, the alignment requirements in a struct can be different from outside of a struct.

On PowerPC-darwin (and powerpc-aix) those testcases will fails also because the struct alignment is different dependent on the placement of the double.

Summary: Don't depend on the alignment of the field's type but rather the field itself.
Comment 2 Bruno Haible 2012-01-27 21:01:11 UTC
I can reproduce the bug with gcc version 4.7-20120121 (snapshot) for x86.
Test program:

===================================================
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <stdalign.h>
int main ()
{
  typedef struct { char slot1; int64_t slot2; } int64_t_helper;
  typedef struct { char slot1; double slot2; } double_helper;
  printf ("%d %d %d\n",
          alignof (int64_t),
          offsetof (int64_t_helper, slot2),
          alignof (int64_t) == offsetof (int64_t_helper, slot2));
  printf ("%d %d %d\n",
          alignof (double),
          offsetof (double_helper, slot2),
          alignof (double) == offsetof (double_helper, slot2));
}
===================================================
Actual output:
8 4 0
8 4 0
Expected output:
4 4 1
4 4 1

(In reply to comment #1)
> I don't think this is a bug, the alignment requirements in a struct can be
> different from outside of a struct.

You could argue like this for __alignof__ which is a GCC invention.

But since ISO C11 and since <stdalign.h> is included, we have to look what
ISO C11 says about it. Citing the latest draft of it (n1570.pdf):

6.5.3.4.(3)
  "The _Alignof operator yields the alignment requirement of its operand type. The
   operand is not evaluated and the result is an integer constant. When applied to
   an array type, the result is the alignment requirement of the element type."

3.2 alignment
  "requirement that objects of a particular type be located on storage boundaries
   with addresses that are particular multiples of a byte address"

3.15 object
  "region of data storage in the execution environment, the contents of which
   can represent values"

As a consequence of these definitions, the alignment of a type inside a struct
could be a multiple of _Alignof(type), but the alignment of a type inside a struct
cannot be less than _Alignof(type).

In other words, if
  alignof (double) == 8
then every 'double' object in memory must be on an address that is a multiple of 8.
Then objects inside the 'double_helper' type must also always be at addresses that
are a multiple of 8. Which by the rules for structs means that
  alignof (double_helper)
and
  offsetof (double_helper, slot2)
must both be multiples of 8.

More about structs in ISO C11:

6.7.2.1.(6)
  "a structure is a type consisting of a sequence of members, whose
   storage is allocated in an ordered sequence"

6.7.2.1.(14)
  "Each non-bit-field member of a structure or union object is aligned in an
   implementation-defined manner appropriate to its type."

Note the last part of the last sentence: "appropriate to its type". The
implementation does not have the freedom to ignore the type's alignment
when deciding about offsetof of a member in a struct.

Please reopen this bug. (I cannot find how to do this witin the bugzilla GUI.)
Comment 3 Andrew Pinski 2012-01-27 21:06:39 UTC
This is really a dup of the old bug 10360:
 A meaningless number.  Because "the alignment used by the compiler"
 is going to depend on the context in which it is used.

*** This bug has been marked as a duplicate of bug 10360 ***
Comment 4 Andrew Pinski 2012-01-27 21:09:53 UTC
One more comment about _Alignof and structures.
Take the following two structures on powerpc-aix (and on powerpc-darwin):
struct
{
  double d;
  int i;
};

struct
{
  int i;
  double d;
};

They have two different alignments.  The first one is the alignment of double and the second is alignment of int.  This is because is how the ABI documents alignment works.
Comment 5 Andrew Pinski 2012-01-27 21:13:29 UTC
(In reply to comment #4)
It gets even worse with the following two structures:
struct
{
  double d;
  char i;
  double d1;
  int i1;
};

struct
{
  char i;
  double d;
  char i1;
  double d1;
};

The second one is packed into 4 byte alignment so the sizeof is 3*8 while the first one is sizeof is 4*8.  So powerpc-aix's alignof double depends on it is a field or not and which field of the structure is first.
Comment 6 Paul Eggert 2012-01-27 21:44:23 UTC
This is not a duplicate of Bug 10360 because that was about
__alignof__, but this one is about the C11 standard _Alignof/alignof.
GCC can assign whatever meaning it likes to __alignof__ but for
_Alignof/alignof it should conform to the standard.  I agree with
Bruno that the bug should be reopened and for now I'm taking the
liberty of doing that until the matter is thought through more
carefully.

In C11, alignof(T) does not mean "the smallest alignment that will
used for T in certain contexts".  It means "the alignment requirement
for T", period; see C11 section 6.5.3.4 paragraph 3.  This alignment
requirement applies to "every object of that type"; see section 6.2.8
paragraph 1.  Members of structures are objects; see section 6.2.5
paragraph 20; and non-bitfield members have addresses and therefore
these addresses must be multiples of their types' alignments.

In short, GCC's behavior clearly conflicts with C11 here.

Andrew gave good ABI examples, where GCC uses different alignments for
T depending on context.  There's nothing wrong with GCC doing that.
All that's required by the standard is that if objects of type T
sometimes have alignment X, and sometimes Y, then alignof(T) must
yield the minimum of X and Y.  (Otherwise, GCC could simply return,
say, 2**20 for alignof(X) regardless of X, on the theory that in
*some* contexts the alignment is 2**20. :-)

Also, this is not simply a question of the C standard.  The GCC manual
says says (about __alignof__) that it "reports the smallest alignment
that GCC will give the data type".  It does not say "the smallest
alignment that GCC will give the data type outside of a struct".  If
the intent is that __alignof__ is supposed to be useful only for some
contexts in a C program, and not others, then the intent conflicts
with GCC's documentation, and either the behavior or the documentation
should be fixed for __alignof__.

As a practical matter, what would be the point of having alignof yield
a value that's greater than the alignment that GCC actually uses for
objects?  What kind of programs would actually make use of this
behavior?  I can certainly think of programs it would *break*, e.g., a
conservative garbage collector that uses alignof to test whether a
purported pointer is actually valid.  On balance, it seems that it'd
be better to conform to the standard here, instead of having a
nonstandard interpretation of alignof.
Comment 7 Andrew Pinski 2012-01-27 21:49:59 UTC
What happens if you have the attribute packed on the structure?  Then guess what _Alignof should always return 1 for all types end of story according to how you interrupt the C standard.
The alignment requirement for double is 8 end of story.  But the alignment in structures is 4.  Those can be different as far as I can tell.  And yes it is a dup because of the same reason why GCC's alignof and _Alignof are the same and are supposed to be the same.

*** This bug has been marked as a duplicate of bug 10360 ***
Comment 8 Paul Eggert 2012-01-27 22:13:13 UTC
> What happens if you have the attribute packed on the structure?

That's not relevant to the standard conformance issue.
Any program that uses __attribute__((packed)) is not a C11 program,
and for such programs C11 does not specify what alignof(double) returns.
The most useful thing for alignof to return is the value that it would return
ignoring the presence of 'packed', as that makes its behavior
simpler and more consistent.  Most likely, if a future version of
C11 specifies structure packing, it'll specify precisely this behavior
for alignof, as it wouldn't be useful to have alignof(X) always return 1.

For strict C11 programs, though, _Alignof(double) cannot return 8 on x86 hosts,
because GCC sometimes allocate 'double' objects on boundaries that
are merely multiples of 4.  The test programs in comment#1 are strict
C11 programs and illustrate the conformance bug.
Comment 9 Bruno Haible 2012-01-27 22:39:01 UTC
(In reply to comment #7)
> What happens if you have the attribute packed on the structure?

Attribute 'packed' is outside the scope of ISO C11. We're discussing ISO C11 compliant programs here.

ISO C11 has the _Alignas keyword, with which a stricter alignment can be requested (ISO C11 6.2.8.(1), 6.7.5.(4)), but not a less strict alignment.

GCC's __alignof__ that returns the *preferred* alignment of an object of the given type has its uses (in memory allocators for example). But the semantics imposed by ISO C11 on the 'alignof' and '_Alignof' operators defined through <stdalign.h> is address boundary requirement for all "objects" of that type, not the preferred alignment.
Comment 10 jsm-csl@polyomino.org.uk 2012-01-27 23:12:38 UTC
I don't think the test programs here are strictly conforming - the offset 
could be bigger than the alignment, and alignments are values 
"representing the number of bytes between successive addresses at which a 
given object can be allocated" which I don't think necessarily have 
literally to count bytes (they may be some other less direct encoding of 
alignment requirements that satisfies the requirements of 6.2.8).  But I 
think the bug is correct; alignof should return the least ABI alignment 
requirement for a type, which is the biggest requirement that the compiler 
can actually rely on when given a pointer to that type.
Comment 11 jsm-csl@polyomino.org.uk 2012-01-27 23:26:39 UTC
I should add: as a matter of ABI compatibility with programs doing what 
stddef.h does for max_align_t (double fields using 
__attribute__((__aligned__(__alignof__(double)))), etc.), it probably is 
best to distinguish between _Alignof (least ABI alignment for a type) and 
__alignof__ (greatest ABI alignment for a type) here.  C++11 will need 
examining to determine what is right for alignof there.  _Alignas(type) 
should of course match _Alignof.  _Alignof (expr) - the C11 keyword 
applied in the GNU extension of alignof (expr) - should continue to have 
the present semantics in the various special cases where the expression 
references a declaration, but otherwise should probably match _Alignof.
Comment 12 Richard Biener 2012-01-30 09:42:04 UTC
Confirmed thus, and a C frontend issue.
Comment 13 Joseph S. Myers 2013-12-04 22:57:23 UTC
Author: jsm28
Date: Wed Dec  4 22:57:20 2013
New Revision: 205685

URL: http://gcc.gnu.org/viewcvs?rev=205685&root=gcc&view=rev
Log:
	PR c/52023
c-family:
	* c-common.c (c_sizeof_or_alignof_type): Add parameter min_alignof
	and check field alignment if set.
	* c-common.h (c_sizeof_or_alignof_type): Update prototype.
	(c_sizeof, c_alignof): Update calls to c_sizeof_or_alignof_type.

c:
	* c-parser.c (c_parser_alignas_specifier): Use
	c_sizeof_or_alignof_type instead of c_alignof.
	(c_parser_alignof_expression): Likewise, with min_alignof
	parameter depending on alignof spelling used.

cp:
	* typeck.c (cxx_sizeof_or_alignof_type): Update call to
	c_sizeof_or_alignof_type.

objc:
	* objc-act.c (objc_synthesize_getter): Update calls to
	c_sizeof_or_alignof_type.

testsuite:
	* gcc.dg/c11-align-6.c: New test.

Added:
    trunk/gcc/testsuite/gcc.dg/c11-align-6.c
Modified:
    trunk/gcc/c-family/ChangeLog
    trunk/gcc/c-family/c-common.c
    trunk/gcc/c-family/c-common.h
    trunk/gcc/c/ChangeLog
    trunk/gcc/c/c-parser.c
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/typeck.c
    trunk/gcc/objc/ChangeLog
    trunk/gcc/objc/objc-act.c
    trunk/gcc/testsuite/ChangeLog
Comment 14 Joseph S. Myers 2013-12-04 22:59:21 UTC
Fixed for 4.9.  The semantics of __alignof__ and C++11 alignof remain, deliberately, the alignment used outside structures.
Comment 15 Jan-Benedict Glaw 2013-12-05 09:56:17 UTC
Some fallout for an unused variable, see eg. http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=50585 :

g++ -c  -DIN_GCC_FRONTEND -DIN_GCC_FRONTEND -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -Werror -fno-common  -DHAVE_CONFIG_H -I. -Ic-family -I../../../gcc/gcc -I../../../gcc/gcc/c-family -I../../../gcc/gcc/../include -I../../../gcc/gcc/../libcpp/include -I/opt/cfarm/mpc/include  -I../../../gcc/gcc/../libdecnumber -I../../../gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I../../../gcc/gcc/../libbacktrace    -o c-family/c-common.o -MT c-family/c-common.o -MMD -MP -MF c-family/.deps/c-common.TPo ../../../gcc/gcc/c-family/c-common.c
../../../gcc/gcc/c-family/c-common.c: In function ‘tree_node* c_sizeof_or_alignof_type(location_t, tree, bool, bool, int)’:
../../../gcc/gcc/c-family/c-common.c:5007:9: error: unused variable ‘field’ [-Werror=unused-variable]
    tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
         ^
cc1plus: all warnings being treated as errors
Comment 16 Marek Polacek 2013-12-05 12:08:17 UTC
(In reply to Jan-Benedict Glaw from comment #15)
> Some fallout for an unused variable, see eg.
> http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=50585 :
> 
> g++ -c  -DIN_GCC_FRONTEND -DIN_GCC_FRONTEND -g -O2 -DIN_GCC 
> -DCROSS_DIRECTORY_STRUCTURE  -fno-exceptions -fno-rtti
> -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings
> -Wcast-qual -Wmissing-format-attribute -pedantic -Wno-long-long
> -Wno-variadic-macros -Wno-overlength-strings -Werror -fno-common 
> -DHAVE_CONFIG_H -I. -Ic-family -I../../../gcc/gcc
> -I../../../gcc/gcc/c-family -I../../../gcc/gcc/../include
> -I../../../gcc/gcc/../libcpp/include -I/opt/cfarm/mpc/include 
> -I../../../gcc/gcc/../libdecnumber -I../../../gcc/gcc/../libdecnumber/dpd
> -I../libdecnumber -I../../../gcc/gcc/../libbacktrace    -o
> c-family/c-common.o -MT c-family/c-common.o -MMD -MP -MF
> c-family/.deps/c-common.TPo ../../../gcc/gcc/c-family/c-common.c
> ../../../gcc/gcc/c-family/c-common.c: In function ‘tree_node*
> c_sizeof_or_alignof_type(location_t, tree, bool, bool, int)’:
> ../../../gcc/gcc/c-family/c-common.c:5007:9: error: unused variable ‘field’
> [-Werror=unused-variable]
>     tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
>          ^
> cc1plus: all warnings being treated as errors

Should be fixed now.
Comment 17 Jan-Benedict Glaw 2014-01-14 10:31:01 UTC
(In reply to Marek Polacek from comment #16)
> >     tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
> >          ^
> > cc1plus: all warnings being treated as errors
> 
> Should be fixed now.

No, not yet. The most recent build for powerpc64-darwin done by my build robot still faces this warning and thus breaks:

http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=89063

--> http://toolchain.lug-owl.de/buildbot/deliver_artifact.php?mode=view&id=733877

So what shall we do with this? The macro is called with two arguments, of which one ("field") isn't used. Just mark it as unused or (void)-cast it away?
Comment 18 Jakub Jelinek 2014-01-14 11:50:51 UTC
(void) cast it away in the Darwin macro.  But that is tracked already in PR59496.
Comment 19 Andrew Pinski 2016-01-30 00:09:04 UTC
*** Bug 69560 has been marked as a duplicate of this bug. ***