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'.
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.
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.)
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 ***
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.
(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.
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.
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 ***
> 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.
(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.
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.
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.
Confirmed thus, and a C frontend issue.
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
Fixed for 4.9. The semantics of __alignof__ and C++11 alignof remain, deliberately, the alignment used outside structures.
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
(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.
(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?
(void) cast it away in the Darwin macro. But that is tracked already in PR59496.
*** Bug 69560 has been marked as a duplicate of this bug. ***