BitfieldGotchas

Assignment from Fake Boolean

In the following example a boolean flag is passed across an interface.

  • In the source object, flags were implemented using an enum.
  • In the destination object they were implemented as a bitfield.
  • The bug was hidden by the use of a C89-style typedeffed BOOL (an int)

The resulting code fails to assign the boolean flag correctly. The bug is a non-issue if C99 stdbool is used instead.

Source

include //printf

if __STDC_VERSION\\ >= 199901

include

typedef _Bool BOOL;  

define FALSE false

else

/* C89 Fake bool */  
typedef int BOOL;  

define FALSE (0)

endif

/* Source data */
enum EFLAGS {
FLAG_NONE = 0x00,
FLAG_FOO = 0x01,
FLAG_BAR = 0x02,
FLAG_MAX
} srcFlags = FLAG_NONE;

struct SFLAGS
{
int isFoo :1;
int isBar :1;
} dstFlags = {, };

int main(void)
{
BOOL tmpBool = FALSE;

srcFlags |= FLAG_BAR; /* set BAR in src */  

tmpBool = (srcFlags & FLAG_BAR); /* pass in BOOL */  
/* fake BOOL: tmpBool has value 2  
 * C99 _Bool: tmpBool has value true  
 */  

dstFlags.isBar = tmpBool; /* set in dst */  
/* fake BOOL: isBar is assigned (2 & 0x01) = 0  !!!  
 * C99 _Bool: isBar is assigned true  
 */  

if (dstFlags.isBar)  
{  
    printf("dstFlags.isBar is TRUE");  
}  
else  
{  
    printf("dstFlags.isBar is FALSE");  
}  

return ;  

}

$[Get Code]1

Results

$ gcc -std=c89 -pedantic -Wall -o bitfield1 bitfield1.c && ./bitfield1
dstFlags.isBar is FALSE

$ gcc -std=c99 -pedantic -Wall -o bitfield1 bitfield1.c && ./bitfield1
dstFlags.isBar is TRUE

Lesson

  • Always sanitise fake BOOL with !!(x) or (x != 0)
  • Or avoid the problem entirely by using C99 _Bool