Bug 144358 - __attribute__((mode(byte))) problems
__attribute__((mode(byte))) problems
Status: CLOSED ERRATA
Product: Fedora
Classification: Fedora
Component: gcc (Show other bugs)
rawhide
All Linux
high Severity high
: ---
: ---
Assigned To: Jakub Jelinek
:
: 144250 (view as bug list)
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2005-01-06 09:51 EST by Jason Vas Dias
Modified: 2007-11-30 17:10 EST (History)
2 users (show)

See Also:
Fixed In Version: 3.4.3-13
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2005-01-22 15:12:46 EST
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Jason Vas Dias 2005-01-06 09:51:36 EST
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:
Comment 1 Jason Vas Dias 2005-01-06 10:05:45 EST
*** Bug 144250 has been marked as a duplicate of this bug. ***
Comment 2 Jakub Jelinek 2005-01-06 10:17:08 EST
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?
Comment 3 Jason Vas Dias 2005-01-06 10:28:40 EST
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 .

Comment 4 Jakub Jelinek 2005-01-06 10:39:36 EST
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.
Comment 6 Jakub Jelinek 2005-01-22 15:12:46 EST
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.
Comment 7 Jason Vas Dias 2005-01-24 16:58:15 EST
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!
Comment 8 Tim Powers 2005-06-09 06:57:22 EDT
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

Note You need to log in before you can comment on or make changes to this bug.