Description of problem: gcc-3.4.3-11 breaks code using __attribute__((mode(byte))) to coerce structure members of enumeration type to have byte (unsigned char) integer type (eg. DHCP) . For example, the code: typedef enum { B1 = 1, B2 = 2, B3 = 4, B4 = 8, B5 = 16, B6 = 32, B7 = 64, B8 = 128 } Bits; struct test { Bits __attribute__((mode(byte))) b1; Bits __attribute__((mode(byte))) b2; }; #include <stdio.h> int main(int argc, char **argv, char **envp) { struct test t; t.b1=B1; t.b2=B2; printf("sizeof(struct test):\t%d\nt.b1:\t%d\nt.b2:\t%d\n",sizeof(struct test),t.b1,t.b2); } When compiled with the default gcc compiler on FC4 (3.4.3-11) with: $ gcc -o mode_byte mode_byte.c the above code produces this output: $ ./mode_byte sizeof(struct test): 2 t.b1: 513 t.b2: 2 Moreover, when the code is run under gdb, gdb reports the size of t.b1 and t.b2 to be 4 bytes each . In DHCP, when a value like t.b1 is compared in a switch statement: switch (lease -> binding_state) { where the 'struct lease' has members: /* Lease states: */ typedef enum { FTS_FREE = 1, FTS_ACTIVE = 2, FTS_EXPIRED = 3, FTS_RELEASED = 4, FTS_ABANDONED = 5, FTS_RESET = 6, FTS_BACKUP = 7 } binding_state_t; struct lease { ... u_int8_t flags; binding_state_t __attribute__ ((mode (__byte__))) binding_state; binding_state_t __attribute__ ((mode (__byte__))) next_binding_state; binding_state_t __attribute__ ((mode (__byte__))) desired_binding_state; struct lease_state *state ... } Some 4 byte integer value composed of the three binding_state_t members and surrounding members is returned - so if the binding_state member is FTS_ACTIVE (2) and the next_binding_state is FTS_FREE (1) then the expression (int)( lease->binding_state ) has the value 257 . This really confuses DHCP, and would need major modification of nearly every source code file in DHCP to circumvent in the code - and I think it is just plain wrong for gcc to behave this way. All gcc versions prior to gcc-3.4.2 supported __attribute__((mode(byte))) fine, so the example program above would print : sizeof(struct test): 2 t.b1: 1 t.b2: 2 Then support for the mode(byte) attribute was broken in gcc-3.4.2, which refused to compile the above code with the error: "error: mode `byte' applied to inappropriate type" This was found to be a gcc bug PR c/18282, which was then fixed in gcc-3.4.3-2, which also compiled the above code fine . gcc4 also has a problem, in that it ignores the mode byte attribute and gives the members a 4-byte size . So the only way to compile DHCP at the moment is with gcc <= 3.3 . Version-Release number of selected component (if applicable): gcc-3.4.3-11 gcc4-4.0.0-0.17 How reproducible: 100% Steps to Reproduce: 1. Compile and run above example program Actual results: $ gcc -o mode_byte mode_byte.c $ ./mode_byte sizeof(struct test): 2 t.b1: 513 t.b2: 2 Expected results: $ gcc -o mode_byte mode_byte.c $ ./mode_byte sizeof(struct test): 2 t.b1: 1 t.b2: 2 Additional info:
*** Bug 144250 has been marked as a duplicate of this bug. ***
All GCCs until now were buggy and compiled this as uint8_t binding_state; instead of binding_state_t __attribute__ ((mode (__byte__))) binding_state; etc. I'll look into this, but is there any reason why you just can't write uint8_t binding_state; etc. in the header?
If the member types were changed to uint8_t, then every assignment like: ' binding_state_t v=FTS_FREE; lease -> binding_state = v; ' would produce a warning , no ? I think I will be doing this anyway, and then deal with all the warnings. But the really buggy part is letting the values of adjacent members get combined in this nasty way, so that when assigning 1 and 2 to t.b1 and t.b2, t.b1 gets the integer value 513 . Also it is disconcerting that gdb thinks the size of each mode(byte) member is 4 .
In C or C++? In C there should be no warnings, in C++ it is a hard error unless -fpermissive. Alternatively, you could also do: struct lease { ... unsigned int flags : 8; binding_state_t binding_state : 8; binding_state_t next_binding_state : 8; binding_state_t desired_binding_state : 8; which should definitely work (e.g. GCC itself uses this heavily), but you might need to reorder the fields depending on endianity if it matters whether flags byte appears in memory first or last.
http://gcc.gnu.org/ml/gcc-patches/2005-01/msg00402.html
Forgot to close this, this is fixed in 3.4.3-13 and later. In 4.0, this exact problem is fixed too, but there are other cases that are still causing ICE, see http://gcc.gnu.org/ml/gcc-patches/2005-01/msg01218.html for details.
Yes, this is definitely now fixed with gcc-3.4.3-16 and gcc4-21 . DHCP can at last be compiled with default gcc and works fine. Many Thanks Jakub!
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHBA-2005-257.html